summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/admin/application_settings_controller_spec.rb40
-rw-r--r--spec/controllers/oauth/authorizations_controller_spec.rb78
-rw-r--r--spec/controllers/profiles/notifications_controller_spec.rb4
-rw-r--r--spec/controllers/projects/deploy_keys_controller_spec.rb38
-rw-r--r--spec/factories/users.rb4
-rw-r--r--spec/features/groups/clusters/user_spec.rb2
-rw-r--r--spec/features/oauth_provider_authorize_spec.rb21
-rw-r--r--spec/features/projects/clusters/user_spec.rb2
-rw-r--r--spec/frontend/clusters/clusters_bundle_spec.js22
-rw-r--r--spec/frontend/fixtures/static/issue_with_mermaid_graph.html82
-rw-r--r--spec/frontend/issue_spec.js27
-rw-r--r--spec/frontend/monitoring/components/duplicate_dashboard_form_spec.js36
-rw-r--r--spec/lib/gitlab/bitbucket_import/importer_spec.rb5
-rw-r--r--spec/lib/gitlab/gl_repository/identifier_spec.rb102
-rw-r--r--spec/lib/gitlab/gl_repository/repo_type_spec.rb22
-rw-r--r--spec/lib/gitlab/gl_repository_spec.rb7
-rw-r--r--spec/lib/gitlab/static_site_editor/config_spec.rb18
-rw-r--r--spec/lib/gitlab/url_sanitizer_spec.rb24
-rw-r--r--spec/models/group_spec.rb5
-rw-r--r--spec/models/notification_setting_spec.rb27
-rw-r--r--spec/models/personal_access_token_spec.rb9
-rw-r--r--spec/models/user_spec.rb167
-rw-r--r--spec/requests/api/graphql/mutations/alert_management/alerts/create_alert_issue_spec.rb74
-rw-r--r--spec/requests/api/group_import_spec.rb33
-rw-r--r--spec/requests/api/notification_settings_spec.rb2
-rw-r--r--spec/requests/api/projects_spec.rb11
-rw-r--r--spec/requests/api/repositories_spec.rb6
-rw-r--r--spec/requests/openid_connect_spec.rb13
-rw-r--r--spec/requests/profiles/notifications_controller_spec.rb4
-rw-r--r--spec/services/clusters/update_service_spec.rb33
-rw-r--r--spec/services/notification_service_spec.rb4
-rw-r--r--spec/support/shared_examples/features/secure_oauth_authorizations_shared_examples.rb19
-rw-r--r--spec/support/shared_examples/lib/gitlab/repo_type_shared_examples.rb20
-rw-r--r--spec/support/shared_examples/mailers/notify_shared_examples.rb1
-rw-r--r--spec/support/shared_examples/uncached_response_shared_examples.rb12
-rw-r--r--spec/views/admin/application_settings/_eks.html.haml_spec.rb34
-rw-r--r--spec/workers/personal_access_tokens/expiring_worker_spec.rb22
-rw-r--r--spec/workers/post_receive_spec.rb2
38 files changed, 905 insertions, 127 deletions
diff --git a/spec/controllers/admin/application_settings_controller_spec.rb b/spec/controllers/admin/application_settings_controller_spec.rb
index 938a30115b0..6980163c49f 100644
--- a/spec/controllers/admin/application_settings_controller_spec.rb
+++ b/spec/controllers/admin/application_settings_controller_spec.rb
@@ -162,6 +162,46 @@ describe Admin::ApplicationSettingsController do
end
end
+ describe 'PATCH #integrations' do
+ before do
+ stub_feature_flags(instance_level_integrations: false)
+ sign_in(admin)
+ end
+
+ describe 'EKS integration' do
+ let(:application_setting) { ApplicationSetting.current }
+ let(:settings_params) do
+ {
+ eks_integration_enabled: '1',
+ eks_account_id: '123456789012',
+ eks_access_key_id: 'dummy access key',
+ eks_secret_access_key: 'dummy secret key'
+ }
+ end
+
+ it 'updates EKS settings' do
+ patch :integrations, params: { application_setting: settings_params }
+
+ expect(application_setting.eks_integration_enabled).to be_truthy
+ expect(application_setting.eks_account_id).to eq '123456789012'
+ expect(application_setting.eks_access_key_id).to eq 'dummy access key'
+ expect(application_setting.eks_secret_access_key).to eq 'dummy secret key'
+ end
+
+ context 'secret access key is blank' do
+ let(:settings_params) { { eks_secret_access_key: '' } }
+
+ it 'does not update the secret key' do
+ application_setting.update!(eks_secret_access_key: 'dummy secret key')
+
+ patch :integrations, params: { application_setting: settings_params }
+
+ expect(application_setting.reload.eks_secret_access_key).to eq 'dummy secret key'
+ end
+ end
+ end
+ end
+
describe 'PUT #reset_registration_token' do
before do
sign_in(admin)
diff --git a/spec/controllers/oauth/authorizations_controller_spec.rb b/spec/controllers/oauth/authorizations_controller_spec.rb
index 1b4bebd9707..f975502ca4e 100644
--- a/spec/controllers/oauth/authorizations_controller_spec.rb
+++ b/spec/controllers/oauth/authorizations_controller_spec.rb
@@ -3,7 +3,6 @@
require 'spec_helper'
describe Oauth::AuthorizationsController do
- let(:user) { create(:user) }
let!(:application) { create(:oauth_application, scopes: 'api read_user', redirect_uri: 'http://example.com') }
let(:params) do
{
@@ -19,53 +18,68 @@ describe Oauth::AuthorizationsController do
end
describe 'GET #new' do
- context 'without valid params' do
- it 'returns 200 code and renders error view' do
- get :new
+ context 'when the user is confirmed' do
+ let(:user) { create(:user) }
- expect(response).to have_gitlab_http_status(:ok)
- expect(response).to render_template('doorkeeper/authorizations/error')
+ context 'without valid params' do
+ it 'returns 200 code and renders error view' do
+ get :new
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to render_template('doorkeeper/authorizations/error')
+ end
end
- end
- context 'with valid params' do
- render_views
+ context 'with valid params' do
+ render_views
- it 'returns 200 code and renders view' do
- get :new, params: params
+ it 'returns 200 code and renders view' do
+ get :new, params: params
- expect(response).to have_gitlab_http_status(:ok)
- expect(response).to render_template('doorkeeper/authorizations/new')
- end
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to render_template('doorkeeper/authorizations/new')
+ end
- it 'deletes session.user_return_to and redirects when skip authorization' do
- application.update(trusted: true)
- request.session['user_return_to'] = 'http://example.com'
+ it 'deletes session.user_return_to and redirects when skip authorization' do
+ application.update(trusted: true)
+ request.session['user_return_to'] = 'http://example.com'
- get :new, params: params
+ get :new, params: params
- expect(request.session['user_return_to']).to be_nil
- expect(response).to have_gitlab_http_status(:found)
- end
+ expect(request.session['user_return_to']).to be_nil
+ expect(response).to have_gitlab_http_status(:found)
+ end
- context 'when there is already an access token for the application' do
- context 'when the request scope matches any of the created token scopes' do
- before do
- scopes = Doorkeeper::OAuth::Scopes.from_string('api')
+ context 'when there is already an access token for the application' do
+ context 'when the request scope matches any of the created token scopes' do
+ before do
+ scopes = Doorkeeper::OAuth::Scopes.from_string('api')
- allow(Doorkeeper.configuration).to receive(:scopes).and_return(scopes)
+ allow(Doorkeeper.configuration).to receive(:scopes).and_return(scopes)
- create :oauth_access_token, application: application, resource_owner_id: user.id, scopes: scopes
- end
+ create :oauth_access_token, application: application, resource_owner_id: user.id, scopes: scopes
+ end
- it 'authorizes the request and redirects' do
- get :new, params: params
+ it 'authorizes the request and redirects' do
+ get :new, params: params
- expect(request.session['user_return_to']).to be_nil
- expect(response).to have_gitlab_http_status(:found)
+ expect(request.session['user_return_to']).to be_nil
+ expect(response).to have_gitlab_http_status(:found)
+ end
end
end
end
end
+
+ context 'when the user is unconfirmed' do
+ let(:user) { create(:user, confirmed_at: nil) }
+
+ it 'returns 200 and renders error view' do
+ get :new, params: params
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to render_template('doorkeeper/authorizations/error')
+ end
+ end
end
end
diff --git a/spec/controllers/profiles/notifications_controller_spec.rb b/spec/controllers/profiles/notifications_controller_spec.rb
index 47d6f11fecf..343f29ef687 100644
--- a/spec/controllers/profiles/notifications_controller_spec.rb
+++ b/spec/controllers/profiles/notifications_controller_spec.rb
@@ -5,8 +5,8 @@ require 'spec_helper'
describe Profiles::NotificationsController do
let(:user) do
create(:user) do |user|
- user.emails.create(email: 'original@example.com')
- user.emails.create(email: 'new@example.com')
+ user.emails.create(email: 'original@example.com', confirmed_at: Time.current)
+ user.emails.create(email: 'new@example.com', confirmed_at: Time.current)
user.notification_email = 'original@example.com'
user.save!
end
diff --git a/spec/controllers/projects/deploy_keys_controller_spec.rb b/spec/controllers/projects/deploy_keys_controller_spec.rb
index 1b2b326b6e9..9d41e2f59cb 100644
--- a/spec/controllers/projects/deploy_keys_controller_spec.rb
+++ b/spec/controllers/projects/deploy_keys_controller_spec.rb
@@ -256,7 +256,7 @@ describe Projects::DeployKeysController do
end
def deploy_key_params(title, can_push)
- deploy_keys_projects_attributes = { '0' => { id: deploy_keys_project, can_push: can_push } }
+ deploy_keys_projects_attributes = { '0' => { can_push: can_push } }
{ deploy_key: { title: title, deploy_keys_projects_attributes: deploy_keys_projects_attributes } }
end
@@ -300,6 +300,42 @@ describe Projects::DeployKeysController do
expect { subject }.to change { deploy_keys_project.reload.can_push }.from(false).to(true)
end
end
+
+ context 'when a different deploy key id param is injected' do
+ let(:extra_params) { deploy_key_params('updated title', '1') }
+ let(:hacked_params) do
+ extra_params.reverse_merge(id: other_deploy_key_id,
+ namespace_id: project.namespace,
+ project_id: project)
+ end
+
+ subject { put :update, params: hacked_params }
+
+ context 'and that deploy key id exists' do
+ let(:other_project) { create(:project) }
+ let(:other_deploy_key) do
+ key = create(:deploy_key)
+ project.deploy_keys << key
+ key
+ end
+
+ let(:other_deploy_key_id) { other_deploy_key.id }
+
+ it 'does not update the can_push attribute' do
+ expect { subject }.not_to change { deploy_key.deploy_keys_project_for(project).can_push }
+ end
+ end
+
+ context 'and that deploy key id does not exist' do
+ let(:other_deploy_key_id) { 9999 }
+
+ it 'returns 404' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
end
context 'with admin as project maintainer' do
diff --git a/spec/factories/users.rb b/spec/factories/users.rb
index 2f5cc404143..7e121b10632 100644
--- a/spec/factories/users.rb
+++ b/spec/factories/users.rb
@@ -48,6 +48,10 @@ FactoryBot.define do
after(:build) { |user, _| user.block! }
end
+ trait :unconfirmed do
+ confirmed_at { nil }
+ end
+
trait :with_avatar do
avatar { fixture_file_upload('spec/fixtures/dk.png') }
end
diff --git a/spec/features/groups/clusters/user_spec.rb b/spec/features/groups/clusters/user_spec.rb
index e9ef66e31a2..a29afba99e4 100644
--- a/spec/features/groups/clusters/user_spec.rb
+++ b/spec/features/groups/clusters/user_spec.rb
@@ -39,7 +39,7 @@ describe 'User Cluster', :js do
expect(page.find_field('cluster[platform_kubernetes_attributes][api_url]').value)
.to have_content('http://example.com')
expect(page.find_field('cluster[platform_kubernetes_attributes][token]').value)
- .to have_content('my-token')
+ .to be_empty
end
end
diff --git a/spec/features/oauth_provider_authorize_spec.rb b/spec/features/oauth_provider_authorize_spec.rb
new file mode 100644
index 00000000000..284fe3b0af9
--- /dev/null
+++ b/spec/features/oauth_provider_authorize_spec.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'OAuth Provider' do
+ describe 'Standard OAuth Authorization' do
+ let(:application) { create(:oauth_application, scopes: 'read_user') }
+
+ before do
+ sign_in(user)
+
+ visit oauth_authorization_path(client_id: application.uid,
+ redirect_uri: application.redirect_uri.split.first,
+ response_type: 'code',
+ state: 'my_state',
+ scope: 'read_user')
+ end
+
+ it_behaves_like 'Secure OAuth Authorizations'
+ end
+end
diff --git a/spec/features/projects/clusters/user_spec.rb b/spec/features/projects/clusters/user_spec.rb
index 79676927fa2..5c82d848563 100644
--- a/spec/features/projects/clusters/user_spec.rb
+++ b/spec/features/projects/clusters/user_spec.rb
@@ -46,7 +46,7 @@ describe 'User Cluster', :js do
expect(page.find_field('cluster[platform_kubernetes_attributes][api_url]').value)
.to have_content('http://example.com')
expect(page.find_field('cluster[platform_kubernetes_attributes][token]').value)
- .to have_content('my-token')
+ .to be_empty
end
it 'user sees RBAC is enabled by default' do
diff --git a/spec/frontend/clusters/clusters_bundle_spec.js b/spec/frontend/clusters/clusters_bundle_spec.js
index d7c648bcd20..9d0ed423759 100644
--- a/spec/frontend/clusters/clusters_bundle_spec.js
+++ b/spec/frontend/clusters/clusters_bundle_spec.js
@@ -82,28 +82,6 @@ describe('Clusters', () => {
});
});
- describe('showToken', () => {
- it('should update token field type', () => {
- cluster.showTokenButton.click();
-
- expect(cluster.tokenField.getAttribute('type')).toEqual('text');
-
- cluster.showTokenButton.click();
-
- expect(cluster.tokenField.getAttribute('type')).toEqual('password');
- });
-
- it('should update show token button text', () => {
- cluster.showTokenButton.click();
-
- expect(cluster.showTokenButton.textContent).toEqual('Hide');
-
- cluster.showTokenButton.click();
-
- expect(cluster.showTokenButton.textContent).toEqual('Show');
- });
- });
-
describe('checkForNewInstalls', () => {
const INITIAL_APP_MAP = {
helm: { status: null, title: 'Helm Tiller' },
diff --git a/spec/frontend/fixtures/static/issue_with_mermaid_graph.html b/spec/frontend/fixtures/static/issue_with_mermaid_graph.html
new file mode 100644
index 00000000000..4b60842a655
--- /dev/null
+++ b/spec/frontend/fixtures/static/issue_with_mermaid_graph.html
@@ -0,0 +1,82 @@
+<div class="description" updated-at="">
+ <div class="md issue-realtime-trigger-pulse">
+ <svg
+ id="mermaid-1587752414912"
+ width="100%"
+ xmlns="http://www.w3.org/2000/svg"
+ style="max-width: 185.35000610351562px;"
+ viewBox="0 0 185.35000610351562 50.5"
+ class="mermaid"
+ >
+ <g transform="translate(0, 0)">
+ <g class="output">
+ <g class="clusters"></g>
+ <g class="edgePaths"></g>
+ <g class="edgeLabels"></g>
+ <g class="nodes">
+ <g
+ class="node js-issuable-actions btn-close clickable"
+ style="opacity: 1;"
+ id="A"
+ transform="translate(92.67500305175781,25.25)"
+ title="click to PUT"
+ >
+ <a
+ class="js-issuable-actions btn-close clickable"
+ href="https://invalid"
+ rel="noopener"
+ >
+ <rect
+ rx="0"
+ ry="0"
+ x="-84.67500305175781"
+ y="-17.25"
+ width="169.35000610351562"
+ height="34.5"
+ class="label-container"
+ ></rect>
+ <g class="label" transform="translate(0,0)">
+ <g transform="translate(-74.67500305175781,-7.25)">
+ <text style="">
+ <tspan xml:space="preserve" dy="1em" x="1">Click to send a PUT request</tspan>
+ </text>
+ </g>
+ </g>
+ </a>
+ </g>
+ </g>
+ </g>
+ </g>
+ <text class="source" display="none">
+ Click to send a PUT request
+ </text>
+ </svg>
+ </div>
+ <textarea
+ data-update-url="/h5bp/html5-boilerplate/-/issues/35.json"
+ dir="auto"
+ class="hidden js-task-list-field"
+ ></textarea>
+ <div class="modal-open recaptcha-modal js-recaptcha-modal" style="display: none;">
+ <div role="dialog" tabindex="-1" class="modal d-block">
+ <div role="document" class="modal-dialog">
+ <div class="modal-content">
+ <div class="modal-header">
+ <h4 class="modal-title float-left">Please solve the reCAPTCHA</h4>
+ <button type="button" data-dismiss="modal" aria-label="Close" class="close float-right">
+ <span aria-hidden="true">×</span>
+ </button>
+ </div>
+ <div class="modal-body">
+ <div>
+ <p>We want to be sure it is you, please confirm you are not a robot.</p>
+ <div></div>
+ </div>
+ </div>
+ <!---->
+ </div>
+ </div>
+ </div>
+ <div class="modal-backdrop fade show"></div>
+ </div>
+</div>
diff --git a/spec/frontend/issue_spec.js b/spec/frontend/issue_spec.js
index 586bd7f8529..24020daf728 100644
--- a/spec/frontend/issue_spec.js
+++ b/spec/frontend/issue_spec.js
@@ -18,6 +18,7 @@ describe('Issue', () => {
preloadFixtures('issues/closed-issue.html');
preloadFixtures('issues/issue-with-task-list.html');
preloadFixtures('issues/open-issue.html');
+ preloadFixtures('static/issue_with_mermaid_graph.html');
function expectErrorMessage() {
const $flashMessage = $('div.flash-alert');
@@ -228,4 +229,30 @@ describe('Issue', () => {
});
});
});
+
+ describe('when not displaying blocked warning', () => {
+ describe('when clicking a mermaid graph inside an issue description', () => {
+ let mock;
+ let spy;
+
+ beforeEach(() => {
+ loadFixtures('static/issue_with_mermaid_graph.html');
+ mock = new MockAdapter(axios);
+ spy = jest.spyOn(axios, 'put');
+ });
+
+ afterEach(() => {
+ mock.restore();
+ jest.clearAllMocks();
+ });
+
+ it('does not make a PUT request', () => {
+ Issue.prototype.initIssueBtnEventListeners();
+
+ $('svg a.js-issuable-actions').trigger('click');
+
+ expect(spy).not.toHaveBeenCalled();
+ });
+ });
+ });
});
diff --git a/spec/frontend/monitoring/components/duplicate_dashboard_form_spec.js b/spec/frontend/monitoring/components/duplicate_dashboard_form_spec.js
index 216ec345552..8ab7c8b9e50 100644
--- a/spec/frontend/monitoring/components/duplicate_dashboard_form_spec.js
+++ b/spec/frontend/monitoring/components/duplicate_dashboard_form_spec.js
@@ -3,9 +3,17 @@ import DuplicateDashboardForm from '~/monitoring/components/duplicate_dashboard_
import { dashboardGitResponse } from '../mock_data';
-describe('DuplicateDashboardForm', () => {
- let wrapper;
+let wrapper;
+
+const createMountedWrapper = (props = {}) => {
+ // Use `mount` to render native input elements
+ wrapper = mount(DuplicateDashboardForm, {
+ propsData: { ...props },
+ sync: false,
+ });
+};
+describe('DuplicateDashboardForm', () => {
const defaultBranch = 'master';
const findByRef = ref => wrapper.find({ ref });
@@ -20,14 +28,7 @@ describe('DuplicateDashboardForm', () => {
};
beforeEach(() => {
- // Use `mount` to render native input elements
- wrapper = mount(DuplicateDashboardForm, {
- propsData: {
- dashboard: dashboardGitResponse[0],
- defaultBranch,
- },
- sync: false,
- });
+ createMountedWrapper({ dashboard: dashboardGitResponse[0], defaultBranch });
});
it('renders correctly', () => {
@@ -146,3 +147,18 @@ describe('DuplicateDashboardForm', () => {
});
});
});
+
+describe('DuplicateDashboardForm escapes elements', () => {
+ const branchToEscape = "<img/src='x'onerror=alert(document.domain)>";
+
+ beforeEach(() => {
+ createMountedWrapper({ dashboard: dashboardGitResponse[0], defaultBranch: branchToEscape });
+ });
+
+ it('should escape branch name data', () => {
+ const branchOptionHtml = wrapper.vm.branchOptions[0].html;
+ const escapedBranch = '&lt;img/src=&#39;x&#39;onerror=alert(document.domain)&gt';
+
+ expect(branchOptionHtml).toEqual(expect.stringContaining(escapedBranch));
+ });
+});
diff --git a/spec/lib/gitlab/bitbucket_import/importer_spec.rb b/spec/lib/gitlab/bitbucket_import/importer_spec.rb
index b3c1f86c5ee..137d0fd4f9e 100644
--- a/spec/lib/gitlab/bitbucket_import/importer_spec.rb
+++ b/spec/lib/gitlab/bitbucket_import/importer_spec.rb
@@ -190,11 +190,14 @@ describe Gitlab::BitbucketImport::Importer do
context 'when importing a pull request throws an exception' do
before do
- allow(pull_request).to receive(:raw).and_return('hello world')
+ allow(pull_request).to receive(:raw).and_return({ error: "broken" })
allow(subject.client).to receive(:pull_request_comments).and_raise(Gitlab::HTTP::Error)
end
it 'logs an error without the backtrace' do
+ expect(Gitlab::ErrorTracking).to receive(:log_exception)
+ .with(instance_of(Gitlab::HTTP::Error), hash_including(raw_response: '{"error":"broken"}'))
+
subject.execute
expect(subject.errors.count).to eq(1)
diff --git a/spec/lib/gitlab/gl_repository/identifier_spec.rb b/spec/lib/gitlab/gl_repository/identifier_spec.rb
new file mode 100644
index 00000000000..eb834494a39
--- /dev/null
+++ b/spec/lib/gitlab/gl_repository/identifier_spec.rb
@@ -0,0 +1,102 @@
+# frozen_string_literal: true
+require 'spec_helper'
+
+describe Gitlab::GlRepository::Identifier do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:personal_snippet) { create(:personal_snippet, author: project.owner) }
+ let_it_be(:project_snippet) { create(:project_snippet, project: project, author: project.owner) }
+ let_it_be(:group) { create(:group) }
+
+ shared_examples 'parsing gl_repository identifier' do
+ subject { described_class.new(identifier) }
+
+ it 'returns correct information' do
+ aggregate_failures do
+ expect(subject.repo_type).to eq(expected_type)
+ expect(subject.fetch_container!).to eq(expected_container)
+ end
+ end
+ end
+
+ describe 'project repository' do
+ it_behaves_like 'parsing gl_repository identifier' do
+ let(:record_id) { project.id }
+ let(:identifier) { "project-#{record_id}" }
+ let(:expected_container) { project }
+ let(:expected_type) { Gitlab::GlRepository::PROJECT }
+ end
+ end
+
+ describe 'wiki' do
+ it_behaves_like 'parsing gl_repository identifier' do
+ let(:record_id) { project.id }
+ let(:identifier) { "wiki-#{record_id}" }
+ let(:expected_container) { project }
+ let(:expected_type) { Gitlab::GlRepository::WIKI }
+ end
+
+ context 'group wiki' do
+ it_behaves_like 'parsing gl_repository identifier' do
+ let(:record_id) { group.id }
+ let(:identifier) { "group-#{record_id}-wiki" }
+ let(:expected_container) { group }
+ let(:expected_type) { Gitlab::GlRepository::WIKI }
+ end
+ end
+ end
+
+ describe 'snippet' do
+ context 'when PersonalSnippet' do
+ it_behaves_like 'parsing gl_repository identifier' do
+ let(:record_id) { personal_snippet.id }
+ let(:identifier) { "snippet-#{record_id}" }
+ let(:expected_container) { personal_snippet }
+ let(:expected_type) { Gitlab::GlRepository::SNIPPET }
+ end
+ end
+
+ context 'when ProjectSnippet' do
+ it_behaves_like 'parsing gl_repository identifier' do
+ let(:record_id) { project_snippet.id }
+ let(:identifier) { "snippet-#{record_id}" }
+ let(:expected_container) { project_snippet }
+ let(:expected_type) { Gitlab::GlRepository::SNIPPET }
+ end
+ end
+ end
+
+ describe 'design' do
+ it_behaves_like 'parsing gl_repository identifier' do
+ let(:record_id) { project.id }
+ let(:identifier) { "design-#{project.id}" }
+ let(:expected_container) { project }
+ let(:expected_type) { Gitlab::GlRepository::DESIGN }
+ end
+ end
+
+ describe 'incorrect format' do
+ def expect_error_raised_for(identifier)
+ expect { described_class.new(identifier) }.to raise_error(ArgumentError)
+ end
+
+ it 'raises error for incorrect id' do
+ expect_error_raised_for('wiki-noid')
+ end
+
+ it 'raises error for incorrect type' do
+ expect_error_raised_for('foo-2')
+ end
+
+ it 'raises error for incorrect three-segments container' do
+ expect_error_raised_for('snippet-2-wiki')
+ end
+
+ it 'raises error for one segment' do
+ expect_error_raised_for('snippet')
+ end
+
+ it 'raises error for for than three segments' do
+ expect_error_raised_for('project-1-wiki-bar')
+ end
+ end
+end
diff --git a/spec/lib/gitlab/gl_repository/repo_type_spec.rb b/spec/lib/gitlab/gl_repository/repo_type_spec.rb
index bf6df55b71e..829de84c506 100644
--- a/spec/lib/gitlab/gl_repository/repo_type_spec.rb
+++ b/spec/lib/gitlab/gl_repository/repo_type_spec.rb
@@ -13,7 +13,7 @@ describe Gitlab::GlRepository::RepoType do
describe Gitlab::GlRepository::PROJECT do
it_behaves_like 'a repo type' do
- let(:expected_id) { project.id.to_s }
+ let(:expected_id) { project.id }
let(:expected_identifier) { "project-#{expected_id}" }
let(:expected_suffix) { '' }
let(:expected_container) { project }
@@ -42,7 +42,7 @@ describe Gitlab::GlRepository::RepoType do
describe Gitlab::GlRepository::WIKI do
it_behaves_like 'a repo type' do
- let(:expected_id) { project.id.to_s }
+ let(:expected_id) { project.id }
let(:expected_identifier) { "wiki-#{expected_id}" }
let(:expected_suffix) { '.wiki' }
let(:expected_container) { project }
@@ -67,12 +67,24 @@ describe Gitlab::GlRepository::RepoType do
expect(described_class.valid?(design_path)).to be_falsey
end
end
+
+ context 'group wiki' do
+ let_it_be(:group) { create(:group) }
+
+ it_behaves_like 'a repo type' do
+ let(:expected_id) { group.id }
+ let(:expected_identifier) { "group-#{expected_id}-wiki" }
+ let(:expected_suffix) { '.wiki' }
+ let(:expected_container) { group }
+ let(:expected_repository) { expected_container.wiki.repository }
+ end
+ end
end
describe Gitlab::GlRepository::SNIPPET do
context 'when PersonalSnippet' do
it_behaves_like 'a repo type' do
- let(:expected_id) { personal_snippet.id.to_s }
+ let(:expected_id) { personal_snippet.id }
let(:expected_identifier) { "snippet-#{expected_id}" }
let(:expected_suffix) { '' }
let(:expected_repository) { personal_snippet.repository }
@@ -101,7 +113,7 @@ describe Gitlab::GlRepository::RepoType do
context 'when ProjectSnippet' do
it_behaves_like 'a repo type' do
- let(:expected_id) { project_snippet.id.to_s }
+ let(:expected_id) { project_snippet.id }
let(:expected_identifier) { "snippet-#{expected_id}" }
let(:expected_suffix) { '' }
let(:expected_repository) { project_snippet.repository }
@@ -131,7 +143,7 @@ describe Gitlab::GlRepository::RepoType do
describe Gitlab::GlRepository::DESIGN do
it_behaves_like 'a repo type' do
let(:expected_identifier) { "design-#{project.id}" }
- let(:expected_id) { project.id.to_s }
+ let(:expected_id) { project.id }
let(:expected_suffix) { '.design' }
let(:expected_repository) { project.design_repository }
let(:expected_container) { project }
diff --git a/spec/lib/gitlab/gl_repository_spec.rb b/spec/lib/gitlab/gl_repository_spec.rb
index 5f5244b7116..1546fd433bc 100644
--- a/spec/lib/gitlab/gl_repository_spec.rb
+++ b/spec/lib/gitlab/gl_repository_spec.rb
@@ -5,16 +5,21 @@ require 'spec_helper'
describe ::Gitlab::GlRepository do
describe '.parse' do
let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:group) { create(:group) }
let_it_be(:snippet) { create(:personal_snippet) }
it 'parses a project gl_repository' do
expect(described_class.parse("project-#{project.id}")).to eq([project, project, Gitlab::GlRepository::PROJECT])
end
- it 'parses a wiki gl_repository' do
+ it 'parses a project wiki gl_repository' do
expect(described_class.parse("wiki-#{project.id}")).to eq([project, project, Gitlab::GlRepository::WIKI])
end
+ it 'parses a group wiki gl_repository' do
+ expect(described_class.parse("group-#{group.id}-wiki")).to eq([group, nil, Gitlab::GlRepository::WIKI])
+ end
+
it 'parses a snippet gl_repository' do
expect(described_class.parse("snippet-#{snippet.id}")).to eq([snippet, nil, Gitlab::GlRepository::SNIPPET])
end
diff --git a/spec/lib/gitlab/static_site_editor/config_spec.rb b/spec/lib/gitlab/static_site_editor/config_spec.rb
index a1db567db1a..4cfda83b8f6 100644
--- a/spec/lib/gitlab/static_site_editor/config_spec.rb
+++ b/spec/lib/gitlab/static_site_editor/config_spec.rb
@@ -65,5 +65,23 @@ describe Gitlab::StaticSiteEditor::Config do
it { is_expected.to include(is_supported_content: 'false') }
end
+
+ context 'when return_url is not a valid URL' do
+ let(:return_url) { 'example.com' }
+
+ it { is_expected.to include(return_url: nil) }
+ end
+
+ context 'when return_url has a javascript scheme' do
+ let(:return_url) { 'javascript:alert(document.domain)' }
+
+ it { is_expected.to include(return_url: nil) }
+ end
+
+ context 'when return_url is missing' do
+ let(:return_url) { nil }
+
+ it { is_expected.to include(return_url: nil) }
+ end
end
end
diff --git a/spec/lib/gitlab/url_sanitizer_spec.rb b/spec/lib/gitlab/url_sanitizer_spec.rb
index b39609c594b..caca22eb98b 100644
--- a/spec/lib/gitlab/url_sanitizer_spec.rb
+++ b/spec/lib/gitlab/url_sanitizer_spec.rb
@@ -60,6 +60,30 @@ describe Gitlab::UrlSanitizer do
end
end
+ describe '.valid_web?' do
+ where(:value, :url) do
+ false | nil
+ false | ''
+ false | '123://invalid:url'
+ false | 'valid@project:url.git'
+ false | 'valid:pass@project:url.git'
+ false | %w(test array)
+ false | 'ssh://example.com'
+ false | 'ssh://:@example.com'
+ false | 'ssh://foo@example.com'
+ false | 'ssh://foo:bar@example.com'
+ false | 'ssh://foo:bar@example.com/group/group/project.git'
+ false | 'git://example.com/group/group/project.git'
+ false | 'git://foo:bar@example.com/group/group/project.git'
+ true | 'http://foo:bar@example.com/group/group/project.git'
+ true | 'https://foo:bar@example.com/group/group/project.git'
+ end
+
+ with_them do
+ it { expect(described_class.valid_web?(url)).to eq(value) }
+ end
+ end
+
describe '#sanitized_url' do
context 'credentials in hash' do
where(username: ['foo', '', nil], password: ['bar', '', nil])
diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb
index a4e49f88115..d6e76258491 100644
--- a/spec/models/group_spec.rb
+++ b/spec/models/group_spec.rb
@@ -110,6 +110,11 @@ describe Group do
let(:group_notification_email) { 'user+group@example.com' }
let(:subgroup_notification_email) { 'user+subgroup@example.com' }
+ before do
+ create(:email, :confirmed, user: user, email: group_notification_email)
+ create(:email, :confirmed, user: user, email: subgroup_notification_email)
+ end
+
subject { subgroup.notification_email_for(user) }
context 'when both group notification emails are set' do
diff --git a/spec/models/notification_setting_spec.rb b/spec/models/notification_setting_spec.rb
index 9ab9ae494ec..67738eaec20 100644
--- a/spec/models/notification_setting_spec.rb
+++ b/spec/models/notification_setting_spec.rb
@@ -48,6 +48,33 @@ RSpec.describe NotificationSetting do
expect(notification_setting.reopen_merge_request).to eq(false)
end
end
+
+ context 'notification_email' do
+ let_it_be(:user) { create(:user) }
+ subject { described_class.new(source_id: 1, source_type: 'Project', user_id: user.id) }
+
+ it 'allows to change email to verified one' do
+ email = create(:email, :confirmed, user: user)
+
+ subject.update(notification_email: email.email)
+
+ expect(subject).to be_valid
+ end
+
+ it 'does not allow to change email to not verified one' do
+ email = create(:email, user: user)
+
+ subject.update(notification_email: email.email)
+
+ expect(subject).to be_invalid
+ end
+
+ it 'allows to change email to empty one' do
+ subject.update(notification_email: '')
+
+ expect(subject).to be_valid
+ end
+ end
end
describe '#for_projects' do
diff --git a/spec/models/personal_access_token_spec.rb b/spec/models/personal_access_token_spec.rb
index 596b11613b3..a3f5eb38511 100644
--- a/spec/models/personal_access_token_spec.rb
+++ b/spec/models/personal_access_token_spec.rb
@@ -178,6 +178,15 @@ describe PersonalAccessToken do
end
end
end
+
+ describe '.without_impersonation' do
+ let_it_be(:impersonation_token) { create(:personal_access_token, :impersonation) }
+ let_it_be(:personal_access_token) { create(:personal_access_token) }
+
+ it 'returns only non-impersonation tokens' do
+ expect(described_class.without_impersonation).to contain_exactly(personal_access_token)
+ end
+ end
end
describe '.simple_sorts' do
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index a9e8bd2d27b..cb78e1015ea 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -311,7 +311,7 @@ describe User do
end
it_behaves_like 'an object with RFC3696 compliant email-formated attributes', :public_email, :notification_email do
- subject { build(:user).tap { |user| user.emails << build(:email, email: email_value) } }
+ subject { create(:user).tap { |user| user.emails << build(:email, email: email_value, confirmed_at: Time.current) } }
end
describe '#commit_email' do
@@ -568,6 +568,32 @@ describe User do
user = build(:user, email: "temp-email-for-oauth@example.com")
expect(user).to be_valid
end
+
+ it 'does not accept not verified emails' do
+ email = create(:email)
+ user = email.user
+ user.update(notification_email: email.email)
+
+ expect(user).to be_invalid
+ end
+ end
+
+ context 'owns_public_email' do
+ it 'accepts verified emails' do
+ email = create(:email, :confirmed, email: 'test@test.com')
+ user = email.user
+ user.update(public_email: email.email)
+
+ expect(user).to be_valid
+ end
+
+ it 'does not accept not verified emails' do
+ email = create(:email)
+ user = email.user
+ user.update(public_email: email.email)
+
+ expect(user).to be_invalid
+ end
end
context 'set_commit_email' do
@@ -791,6 +817,7 @@ describe User do
let_it_be(:expired_token) { create(:personal_access_token, user: user1, expires_at: 2.days.ago) }
let_it_be(:revoked_token) { create(:personal_access_token, user: user1, revoked: true) }
+ let_it_be(:impersonation_token) { create(:personal_access_token, :impersonation, user: user1, expires_at: 2.days.from_now) }
let_it_be(:valid_token_and_notified) { create(:personal_access_token, user: user2, expires_at: 2.days.from_now, expire_notification_delivered: true) }
let_it_be(:valid_token1) { create(:personal_access_token, user: user2, expires_at: 2.days.from_now) }
let_it_be(:valid_token2) { create(:personal_access_token, user: user2, expires_at: 2.days.from_now) }
@@ -917,6 +944,108 @@ describe User do
expect(@user.emails.count).to eq 1
expect(@user.emails.first.confirmed_at).not_to eq nil
end
+
+ context 'when the first email was unconfirmed and the second email gets confirmed' do
+ let(:user) { create(:user, :unconfirmed, email: 'should-be-unconfirmed@test.com') }
+
+ before do
+ user.update!(email: 'should-be-confirmed@test.com')
+ user.confirm
+ end
+
+ it 'updates user.email' do
+ expect(user.email).to eq('should-be-confirmed@test.com')
+ end
+
+ it 'confirms user.email' do
+ expect(user).to be_confirmed
+ end
+
+ it 'keeps the unconfirmed email unconfirmed' do
+ email = user.emails.first
+
+ expect(email.email).to eq('should-be-unconfirmed@test.com')
+ expect(email).not_to be_confirmed
+ end
+
+ it 'has only one email association' do
+ expect(user.emails.size).to eq(1)
+ end
+ end
+ end
+
+ context 'when an existing email record is set as primary' do
+ let(:user) { create(:user, email: 'confirmed@test.com') }
+
+ context 'when it is unconfirmed' do
+ let(:originally_unconfirmed_email) { 'should-stay-unconfirmed@test.com' }
+
+ before do
+ user.emails << create(:email, email: originally_unconfirmed_email, confirmed_at: nil)
+
+ user.update!(email: originally_unconfirmed_email)
+ end
+
+ it 'keeps the user confirmed' do
+ expect(user).to be_confirmed
+ end
+
+ it 'keeps the original email' do
+ expect(user.email).to eq('confirmed@test.com')
+ end
+
+ context 'when the email gets confirmed' do
+ before do
+ user.confirm
+ end
+
+ it 'keeps the user confirmed' do
+ expect(user).to be_confirmed
+ end
+
+ it 'updates the email' do
+ expect(user.email).to eq(originally_unconfirmed_email)
+ end
+ end
+ end
+
+ context 'when it is confirmed' do
+ let!(:old_confirmed_email) { user.email }
+ let(:confirmed_email) { 'already-confirmed@test.com' }
+
+ before do
+ user.emails << create(:email, :confirmed, email: confirmed_email)
+
+ user.update!(email: confirmed_email)
+ end
+
+ it 'keeps the user confirmed' do
+ expect(user).to be_confirmed
+ end
+
+ it 'updates the email' do
+ expect(user.email).to eq(confirmed_email)
+ end
+
+ it 'moves the old email' do
+ email = user.reload.emails.first
+
+ expect(email.email).to eq(old_confirmed_email)
+ expect(email).to be_confirmed
+ end
+ end
+ end
+
+ context 'when unconfirmed user deletes a confirmed additional email' do
+ let(:user) { create(:user, :unconfirmed) }
+
+ before do
+ user.emails << create(:email, :confirmed)
+ end
+
+ it 'does not affect the confirmed status' do
+ expect { user.emails.confirmed.destroy_all }.not_to change { user.confirmed? } # rubocop: disable Cop/DestroyAll
+ end
end
describe '#update_notification_email' do
@@ -2070,6 +2199,31 @@ describe User do
end
end
+ describe '#public_verified_emails' do
+ let(:user) { create(:user) }
+
+ it 'returns only confirmed public emails' do
+ email_confirmed = create :email, user: user, confirmed_at: Time.current
+ create :email, user: user
+
+ expect(user.public_verified_emails).to contain_exactly(
+ user.email,
+ email_confirmed.email
+ )
+ end
+
+ it 'returns confirmed public emails plus main user email when user is not confirmed' do
+ user = create(:user, confirmed_at: nil)
+ email_confirmed = create :email, user: user, confirmed_at: Time.current
+ create :email, user: user
+
+ expect(user.public_verified_emails).to contain_exactly(
+ user.email,
+ email_confirmed.email
+ )
+ end
+ end
+
describe '#verified_email?' do
let(:user) { create(:user) }
@@ -4200,9 +4354,10 @@ describe User do
context 'when an ancestor has a level other than Global' do
let(:ancestor) { create(:group) }
let(:group) { create(:group, parent: ancestor) }
+ let(:email) { create(:email, :confirmed, email: 'ancestor@example.com', user: user) }
before do
- create(:notification_setting, user: user, source: ancestor, level: 'participating', notification_email: 'ancestor@example.com')
+ create(:notification_setting, user: user, source: ancestor, level: 'participating', notification_email: email.email)
end
it 'has the same level set' do
@@ -4227,10 +4382,12 @@ describe User do
let(:grand_ancestor) { create(:group) }
let(:ancestor) { create(:group, parent: grand_ancestor) }
let(:group) { create(:group, parent: ancestor) }
+ let(:ancestor_email) { create(:email, :confirmed, email: 'ancestor@example.com', user: user) }
+ let(:grand_email) { create(:email, :confirmed, email: 'grand@example.com', user: user) }
before do
- create(:notification_setting, user: user, source: grand_ancestor, level: 'participating', notification_email: 'grand@example.com')
- create(:notification_setting, user: user, source: ancestor, level: 'global', notification_email: 'ancestor@example.com')
+ create(:notification_setting, user: user, source: grand_ancestor, level: 'participating', notification_email: grand_email.email)
+ create(:notification_setting, user: user, source: ancestor, level: 'global', notification_email: ancestor_email.email)
end
it 'has the same email set' do
@@ -4268,7 +4425,7 @@ describe User do
context 'when group has notification email set' do
it 'returns group notification email' do
group_notification_email = 'user+group@example.com'
-
+ create(:email, :confirmed, user: user, email: group_notification_email)
create(:notification_setting, user: user, source: group, notification_email: group_notification_email)
is_expected.to eq(group_notification_email)
diff --git a/spec/requests/api/graphql/mutations/alert_management/alerts/create_alert_issue_spec.rb b/spec/requests/api/graphql/mutations/alert_management/alerts/create_alert_issue_spec.rb
new file mode 100644
index 00000000000..5b5b2ec8788
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/alert_management/alerts/create_alert_issue_spec.rb
@@ -0,0 +1,74 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'Create an alert issue from an alert' do
+ include GraphqlHelpers
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:alert) { create(:alert_management_alert, project: project) }
+
+ let(:mutation) do
+ variables = {
+ project_path: project.full_path,
+ iid: alert.iid.to_s
+ }
+ graphql_mutation(:create_alert_issue, variables,
+ <<~QL
+ clientMutationId
+ errors
+ alert {
+ iid
+ issueIid
+ }
+ issue {
+ iid
+ title
+ }
+ QL
+ )
+ end
+
+ let(:mutation_response) { graphql_mutation_response(:create_alert_issue) }
+
+ before do
+ project.add_developer(user)
+ end
+
+ context 'when there is no issue associated with the alert' do
+ it 'creates an alert issue' do
+ post_graphql_mutation(mutation, current_user: user)
+
+ new_issue = Issue.last!
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(mutation_response.slice('alert', 'issue')).to eq(
+ 'alert' => {
+ 'iid' => alert.iid.to_s,
+ 'issueIid' => new_issue.iid.to_s
+ },
+ 'issue' => {
+ 'iid' => new_issue.iid.to_s,
+ 'title' => new_issue.title
+ }
+ )
+ end
+ end
+
+ context 'when there is an issue already associated with the alert' do
+ before do
+ AlertManagement::CreateAlertIssueService.new(alert, user).execute
+ end
+
+ it 'responds with an error' do
+ post_graphql_mutation(mutation, current_user: user)
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(mutation_response.slice('errors', 'issue')).to eq(
+ 'errors' => ['An issue already exists'],
+ 'issue' => nil
+ )
+ end
+ end
+end
diff --git a/spec/requests/api/group_import_spec.rb b/spec/requests/api/group_import_spec.rb
index 58bff08dcbb..b60a1b3f119 100644
--- a/spec/requests/api/group_import_spec.rb
+++ b/spec/requests/api/group_import_spec.rb
@@ -11,7 +11,7 @@ describe API::GroupImport do
let(:file) { File.join('spec', 'fixtures', 'group_export.tar.gz') }
let(:export_path) { "#{Dir.tmpdir}/group_export_spec" }
let(:workhorse_token) { JWT.encode({ 'iss' => 'gitlab-workhorse' }, Gitlab::Workhorse.secret, 'HS256') }
- let(:workhorse_header) { { 'GitLab-Workhorse' => '1.0', Gitlab::Workhorse::INTERNAL_API_REQUEST_HEADER => workhorse_token } }
+ let(:workhorse_headers) { { 'GitLab-Workhorse' => '1.0', Gitlab::Workhorse::INTERNAL_API_REQUEST_HEADER => workhorse_token } }
before do
allow_next_instance_of(Gitlab::ImportExport) do |import_export|
@@ -35,7 +35,7 @@ describe API::GroupImport do
}
end
- subject { post api('/groups/import', user), params: params, headers: workhorse_header }
+ subject { upload_archive(file_upload, workhorse_headers, params) }
shared_examples 'when all params are correct' do
context 'when user is authorized to create new group' do
@@ -151,7 +151,7 @@ describe API::GroupImport do
params[:file] = file_upload
expect do
- post api('/groups/import', user), params: params, headers: workhorse_header
+ upload_archive(file_upload, workhorse_headers, params)
end.not_to change { Group.count }.from(1)
expect(response).to have_gitlab_http_status(:bad_request)
@@ -171,7 +171,7 @@ describe API::GroupImport do
context 'without a file from workhorse' do
it 'rejects the request' do
- subject
+ upload_archive(nil, workhorse_headers, params)
expect(response).to have_gitlab_http_status(:bad_request)
end
@@ -179,7 +179,7 @@ describe API::GroupImport do
context 'without a workhorse header' do
it 'rejects request without a workhorse header' do
- post api('/groups/import', user), params: params
+ upload_archive(file_upload, {}, params)
expect(response).to have_gitlab_http_status(:forbidden)
end
@@ -189,9 +189,7 @@ describe API::GroupImport do
let(:params) do
{
path: 'test-import-group',
- name: 'test-import-group',
- 'file.path' => file_upload.path,
- 'file.name' => file_upload.original_filename
+ name: 'test-import-group'
}
end
@@ -229,9 +227,7 @@ describe API::GroupImport do
{
path: 'test-import-group',
name: 'test-import-group',
- file: fog_file,
- 'file.remote_id' => file_name,
- 'file.size' => fog_file.size
+ file: fog_file
}
end
@@ -245,10 +241,21 @@ describe API::GroupImport do
include_examples 'when some params are missing'
end
end
+
+ def upload_archive(file, headers = {}, params = {})
+ workhorse_finalize(
+ api('/groups/import', user),
+ method: :post,
+ file_key: :file,
+ params: params.merge(file: file),
+ headers: headers,
+ send_rewritten_field: true
+ )
+ end
end
describe 'POST /groups/import/authorize' do
- subject { post api('/groups/import/authorize', user), headers: workhorse_header }
+ subject { post api('/groups/import/authorize', user), headers: workhorse_headers }
it 'authorizes importing group with workhorse header' do
subject
@@ -258,7 +265,7 @@ describe API::GroupImport do
end
it 'rejects requests that bypassed gitlab-workhorse' do
- workhorse_header.delete(Gitlab::Workhorse::INTERNAL_API_REQUEST_HEADER)
+ workhorse_headers.delete(Gitlab::Workhorse::INTERNAL_API_REQUEST_HEADER)
subject
diff --git a/spec/requests/api/notification_settings_spec.rb b/spec/requests/api/notification_settings_spec.rb
index cbdab2f53a6..2dfde4c8ec9 100644
--- a/spec/requests/api/notification_settings_spec.rb
+++ b/spec/requests/api/notification_settings_spec.rb
@@ -19,7 +19,7 @@ describe API::NotificationSettings do
end
describe "PUT /notification_settings" do
- let(:email) { create(:email, user: user) }
+ let(:email) { create(:email, :confirmed, user: user) }
it "updates global notification settings for the current user" do
put api("/notification_settings", user), params: { level: 'watch', notification_email: email.email }
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index 2ce13393243..39847451439 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -1891,6 +1891,17 @@ describe API::Projects do
expect(project_fork_target).to be_forked
end
+ it 'fails without permission from forked_from project' do
+ project_fork_source.project_feature.update_attribute(:forking_access_level, ProjectFeature::PRIVATE)
+
+ post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", user)
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ expect(project_fork_target.forked_from_project).to be_nil
+ expect(project_fork_target.fork_network_member).not_to be_present
+ expect(project_fork_target).not_to be_forked
+ end
+
it 'denies project to be forked from a private project' do
post api("/projects/#{project_fork_target.id}/fork/#{private_project_fork_source.id}", user)
diff --git a/spec/requests/api/repositories_spec.rb b/spec/requests/api/repositories_spec.rb
index 0c66bfd6c4d..bfc782c62e5 100644
--- a/spec/requests/api/repositories_spec.rb
+++ b/spec/requests/api/repositories_spec.rb
@@ -177,6 +177,12 @@ describe API::Repositories do
expect(headers['Content-Disposition']).to eq 'inline'
end
+ it_behaves_like 'uncached response' do
+ before do
+ get api(route, current_user)
+ end
+ end
+
context 'when sha does not exist' do
it_behaves_like '404 response' do
let(:request) { get api(route.sub(sample_blob.oid, 'abcd9876'), current_user) }
diff --git a/spec/requests/openid_connect_spec.rb b/spec/requests/openid_connect_spec.rb
index bd270679acd..785ab98a3d0 100644
--- a/spec/requests/openid_connect_spec.rb
+++ b/spec/requests/openid_connect_spec.rb
@@ -9,15 +9,11 @@ describe 'OpenID Connect requests' do
name: 'Alice',
username: 'alice',
email: 'private@example.com',
- emails: [public_email],
- public_email: public_email.email,
website_url: 'https://example.com',
avatar: fixture_file_upload('spec/fixtures/dk.png')
)
end
- let(:public_email) { build :email, email: 'public@example.com' }
-
let(:access_grant) { create :oauth_access_grant, application: application, resource_owner_id: user.id }
let(:access_token) { create :oauth_access_token, application: application, resource_owner_id: user.id }
@@ -37,7 +33,7 @@ describe 'OpenID Connect requests' do
'name' => 'Alice',
'nickname' => 'alice',
'email' => 'public@example.com',
- 'email_verified' => false,
+ 'email_verified' => true,
'website' => 'https://example.com',
'profile' => 'http://localhost/alice',
'picture' => "http://localhost/uploads/-/system/user/avatar/#{user.id}/dk.png",
@@ -62,6 +58,11 @@ describe 'OpenID Connect requests' do
get '/oauth/userinfo', params: {}, headers: { 'Authorization' => "Bearer #{access_token.token}" }
end
+ before do
+ email = create(:email, :confirmed, email: 'public@example.com', user: user)
+ user.update!(public_email: email.email)
+ end
+
context 'Application without OpenID scope' do
let(:application) { create :oauth_application, scopes: 'api' }
@@ -123,7 +124,7 @@ describe 'OpenID Connect requests' do
end
it 'has false in email_verified claim' do
- expect(json_response['email_verified']).to eq(false)
+ expect(json_response['email_verified']).to eq(true)
end
end
diff --git a/spec/requests/profiles/notifications_controller_spec.rb b/spec/requests/profiles/notifications_controller_spec.rb
index 41349d6c12d..0b2741677ab 100644
--- a/spec/requests/profiles/notifications_controller_spec.rb
+++ b/spec/requests/profiles/notifications_controller_spec.rb
@@ -5,8 +5,8 @@ require 'spec_helper'
describe 'view user notifications' do
let(:user) do
create(:user) do |user|
- user.emails.create(email: 'original@example.com')
- user.emails.create(email: 'new@example.com')
+ user.emails.create(email: 'original@example.com', confirmed_at: Time.current)
+ user.emails.create(email: 'new@example.com', confirmed_at: Time.current)
user.notification_email = 'original@example.com'
user.save!
end
diff --git a/spec/services/clusters/update_service_spec.rb b/spec/services/clusters/update_service_spec.rb
index d487edd8850..5a7726eded8 100644
--- a/spec/services/clusters/update_service_spec.rb
+++ b/spec/services/clusters/update_service_spec.rb
@@ -47,6 +47,39 @@ describe Clusters::UpdateService do
expect(cluster.platform.namespace).to eq('custom-namespace')
end
end
+
+ context 'when service token is empty' do
+ let(:params) do
+ {
+ platform_kubernetes_attributes: {
+ token: ''
+ }
+ }
+ end
+
+ it 'does not update the token' do
+ current_token = cluster.platform.token
+ is_expected.to eq(true)
+ cluster.platform.reload
+
+ expect(cluster.platform.token).to eq(current_token)
+ end
+ end
+
+ context 'when service token is not empty' do
+ let(:params) do
+ {
+ platform_kubernetes_attributes: {
+ token: 'new secret token'
+ }
+ }
+ end
+
+ it 'updates the token' do
+ is_expected.to eq(true)
+ expect(cluster.platform.token).to eq('new secret token')
+ end
+ end
end
context 'when invalid params' do
diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb
index d3376ef0a04..9943f2c01ca 100644
--- a/spec/services/notification_service_spec.rb
+++ b/spec/services/notification_service_spec.rb
@@ -2457,6 +2457,8 @@ describe NotificationService, :mailer do
group = create(:group)
project.update(group: group)
+
+ create(:email, :confirmed, user: u_custom_notification_enabled, email: group_notification_email)
create(:notification_setting, user: u_custom_notification_enabled, source: group, notification_email: group_notification_email)
end
@@ -2491,6 +2493,7 @@ describe NotificationService, :mailer do
group = create(:group)
project.update(group: group)
+ create(:email, :confirmed, user: u_member, email: group_notification_email)
create(:notification_setting, user: u_member, source: group, notification_email: group_notification_email)
end
@@ -2584,6 +2587,7 @@ describe NotificationService, :mailer do
group = create(:group)
project.update(group: group)
+ create(:email, :confirmed, user: u_member, email: group_notification_email)
create(:notification_setting, user: u_member, source: group, notification_email: group_notification_email)
end
diff --git a/spec/support/shared_examples/features/secure_oauth_authorizations_shared_examples.rb b/spec/support/shared_examples/features/secure_oauth_authorizations_shared_examples.rb
new file mode 100644
index 00000000000..028e075c87a
--- /dev/null
+++ b/spec/support/shared_examples/features/secure_oauth_authorizations_shared_examples.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'Secure OAuth Authorizations' do
+ context 'when user is confirmed' do
+ let(:user) { create(:user) }
+
+ it 'asks the user to authorize the application' do
+ expect(page).to have_text "Authorize #{application.name} to use your account?"
+ end
+ end
+
+ context 'when user is unconfirmed' do
+ let(:user) { create(:user, confirmed_at: nil) }
+
+ it 'displays an error' do
+ expect(page).to have_text I18n.t('doorkeeper.errors.messages.unconfirmed_email')
+ end
+ end
+end
diff --git a/spec/support/shared_examples/lib/gitlab/repo_type_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/repo_type_shared_examples.rb
index 69ae9339f10..4aeae788114 100644
--- a/spec/support/shared_examples/lib/gitlab/repo_type_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/repo_type_shared_examples.rb
@@ -7,26 +7,6 @@ RSpec.shared_examples 'a repo type' do
it { is_expected.to eq(expected_identifier) }
end
- describe '#fetch_id' do
- it 'finds an id match in the identifier' do
- expect(described_class.fetch_id(expected_identifier)).to eq(expected_id)
- end
-
- it 'does not break on other identifiers' do
- expect(described_class.fetch_id('wiki-noid')).to eq(nil)
- end
- end
-
- describe '#fetch_container!' do
- it 'returns the container' do
- expect(described_class.fetch_container!(expected_identifier)).to eq expected_container
- end
-
- it 'raises an exception if the identifier is invalid' do
- expect { described_class.fetch_container!('project-noid') }.to raise_error ArgumentError
- end
- end
-
describe '#path_suffix' do
subject { described_class.path_suffix }
diff --git a/spec/support/shared_examples/mailers/notify_shared_examples.rb b/spec/support/shared_examples/mailers/notify_shared_examples.rb
index 45987059123..1f5803b90a0 100644
--- a/spec/support/shared_examples/mailers/notify_shared_examples.rb
+++ b/spec/support/shared_examples/mailers/notify_shared_examples.rb
@@ -28,6 +28,7 @@ RSpec.shared_examples 'an email sent to a user' do
it 'is sent to user\'s group notification email' do
group_notification_email = 'user+group@example.com'
+ create(:email, :confirmed, user: recipient, email: group_notification_email)
create(:notification_setting, user: recipient, source: group, notification_email: group_notification_email)
expect(subject).to deliver_to(group_notification_email)
diff --git a/spec/support/shared_examples/uncached_response_shared_examples.rb b/spec/support/shared_examples/uncached_response_shared_examples.rb
new file mode 100644
index 00000000000..3997017ff35
--- /dev/null
+++ b/spec/support/shared_examples/uncached_response_shared_examples.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+#
+# Pairs with lib/gitlab/no_cache_headers.rb
+#
+
+RSpec.shared_examples 'uncached response' do
+ it 'defines an uncached header response' do
+ expect(response.headers["Cache-Control"]).to include("no-store", "no-cache")
+ expect(response.headers["Pragma"]).to eq("no-cache")
+ expect(response.headers["Expires"]).to eq("Fri, 01 Jan 1990 00:00:00 GMT")
+ end
+end
diff --git a/spec/views/admin/application_settings/_eks.html.haml_spec.rb b/spec/views/admin/application_settings/_eks.html.haml_spec.rb
new file mode 100644
index 00000000000..52434557d3a
--- /dev/null
+++ b/spec/views/admin/application_settings/_eks.html.haml_spec.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'admin/application_settings/_eks' do
+ let_it_be(:admin) { create(:admin) }
+ let(:page) { Capybara::Node::Simple.new(rendered) }
+
+ before do
+ assign(:application_setting, application_setting)
+ allow(view).to receive(:current_user) { admin }
+ allow(view).to receive(:expanded) { true }
+ end
+
+ shared_examples 'EKS secret access key input' do
+ it 'renders an empty password field' do
+ render
+ expect(rendered).to have_field('Secret access key', type: 'password')
+ expect(page.find_field('Secret access key').value).to be_blank
+ end
+ end
+
+ context 'when eks_secret_access_key is not set' do
+ let(:application_setting) { build(:application_setting) }
+
+ include_examples 'EKS secret access key input'
+ end
+
+ context 'when eks_secret_access_key is set' do
+ let(:application_setting) { build(:application_setting, eks_secret_access_key: 'eks_secret_access_key') }
+
+ include_examples 'EKS secret access key input'
+ end
+end
diff --git a/spec/workers/personal_access_tokens/expiring_worker_spec.rb b/spec/workers/personal_access_tokens/expiring_worker_spec.rb
index fcc09e2705c..c8bdf02f4d3 100644
--- a/spec/workers/personal_access_tokens/expiring_worker_spec.rb
+++ b/spec/workers/personal_access_tokens/expiring_worker_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe PersonalAccessTokens::ExpiringWorker, type: :worker do
describe '#perform' do
context 'when a token needs to be notified' do
- let!(:pat) { create(:personal_access_token, expires_at: 5.days.from_now) }
+ let_it_be(:pat) { create(:personal_access_token, expires_at: 5.days.from_now) }
it 'uses notification service to send the email' do
expect_next_instance_of(NotificationService) do |notification_service|
@@ -23,7 +23,7 @@ RSpec.describe PersonalAccessTokens::ExpiringWorker, type: :worker do
end
context 'when no tokens need to be notified' do
- let!(:pat) { create(:personal_access_token, expires_at: 5.days.from_now, expire_notification_delivered: true) }
+ let_it_be(:pat) { create(:personal_access_token, expires_at: 5.days.from_now, expire_notification_delivered: true) }
it "doesn't use notification service to send the email" do
expect_next_instance_of(NotificationService) do |notification_service|
@@ -33,7 +33,23 @@ RSpec.describe PersonalAccessTokens::ExpiringWorker, type: :worker do
worker.perform
end
- it "doesn't change the notificationd delivered of the token" do
+ it "doesn't change the notification delivered of the token" do
+ expect { worker.perform }.not_to change { pat.reload.expire_notification_delivered }
+ end
+ end
+
+ context 'when a token is an impersonation token' do
+ let_it_be(:pat) { create(:personal_access_token, :impersonation, expires_at: 5.days.from_now) }
+
+ it "doesn't use notification service to send the email" do
+ expect_next_instance_of(NotificationService) do |notification_service|
+ expect(notification_service).not_to receive(:access_token_about_to_expire).with(pat.user)
+ end
+
+ worker.perform
+ end
+
+ it "doesn't change the notification delivered of the token" do
expect { worker.perform }.not_to change { pat.reload.expire_notification_delivered }
end
end
diff --git a/spec/workers/post_receive_spec.rb b/spec/workers/post_receive_spec.rb
index aab7a36189a..18e06332eb3 100644
--- a/spec/workers/post_receive_spec.rb
+++ b/spec/workers/post_receive_spec.rb
@@ -355,7 +355,7 @@ describe PostReceive do
context "webhook" do
it "fetches the correct project" do
- expect(Project).to receive(:find_by).with(id: project.id.to_s)
+ expect(Project).to receive(:find_by).with(id: project.id)
perform
end