From 02c6800ac51fc1a504f527426d6cc5a780481a1d Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Wed, 6 Apr 2022 21:08:15 +0000 Subject: [PATCH] Add latest changes from gitlab-org/gitlab@master --- .../components/import_status.vue | 133 +++++++++++++++- .../javascripts/import_entities/constants.js | 41 ----- .../components/provider_repo_table_row.vue | 14 +- .../import_projects/store/mutations.js | 6 +- .../subscriptions/components/app.vue | 1 + .../components/subscriptions_list.vue | 8 +- .../components/search_settings.vue | 45 +++--- .../stylesheets/page_bundles/import.scss | 10 +- app/finders/users_finder.rb | 3 +- app/models/ci/secure_file.rb | 9 -- app/models/user.rb | 3 + app/models/user_custom_attribute.rb | 10 ++ ...3350_add_forbidden_state_index_to_users.rb | 17 ++ db/schema_migrations/20220404183350 | 1 + db/structure.sql | 2 + .../reference_architectures/10k_users.md | 44 ++++++ .../reference_architectures/25k_users.md | 44 ++++++ .../reference_architectures/3k_users.md | 44 ++++++ .../reference_architectures/50k_users.md | 44 ++++++ .../reference_architectures/5k_users.md | 44 ++++++ .../gitlab_rails_cheat_sheet.md | 7 + doc/api/secure_files.md | 1 - doc/topics/git/troubleshooting_git.md | 35 +++++ doc/user/project/repository/mirror/index.md | 5 + lib/api/ci/secure_files.rb | 4 +- locale/gitlab.pot | 21 ++- qa/spec/specs/allure_report_spec.rb | 2 +- spec/finders/users_finder_spec.rb | 50 +++--- .../components/import_status_spec.js | 145 ++++++++++++++++++ .../provider_repo_table_row_spec.js | 7 + .../import_projects/store/mutations_spec.js | 29 ++++ .../components/search_settings_spec.js | 41 +++-- spec/models/user_spec.rb | 17 ++ spec/requests/api/ci/secure_files_spec.rb | 32 ---- spec/requests/api/users_spec.rb | 4 +- .../finders/users_finder_shared_contexts.rb | 4 +- 36 files changed, 751 insertions(+), 176 deletions(-) create mode 100644 db/post_migrate/20220404183350_add_forbidden_state_index_to_users.rb create mode 100644 db/schema_migrations/20220404183350 create mode 100644 spec/frontend/import_entities/components/import_status_spec.js diff --git a/app/assets/javascripts/import_entities/components/import_status.vue b/app/assets/javascripts/import_entities/components/import_status.vue index cc6a057f587..9262a4e1e95 100644 --- a/app/assets/javascripts/import_entities/components/import_status.vue +++ b/app/assets/javascripts/import_entities/components/import_status.vue @@ -1,10 +1,66 @@ diff --git a/app/assets/javascripts/import_entities/constants.js b/app/assets/javascripts/import_entities/constants.js index 1ab5413a5cc..20a4d2d84b4 100644 --- a/app/assets/javascripts/import_entities/constants.js +++ b/app/assets/javascripts/import_entities/constants.js @@ -1,5 +1,3 @@ -import { __ } from '~/locale'; - // The `scheduling` status is only present on the client-side, // it is used as the status when we are requesting to start an import. @@ -13,42 +11,3 @@ export const STATUSES = { SCHEDULING: 'scheduling', CANCELLED: 'cancelled', }; - -const SCHEDULED_STATUS = { - icon: 'status-scheduled', - text: __('Pending'), - iconClass: 'gl-text-orange-400', -}; - -const STATUS_MAP = { - [STATUSES.NONE]: { - icon: 'status-waiting', - text: __('Not started'), - iconClass: 'gl-text-gray-400', - }, - [STATUSES.SCHEDULING]: SCHEDULED_STATUS, - [STATUSES.SCHEDULED]: SCHEDULED_STATUS, - [STATUSES.CREATED]: SCHEDULED_STATUS, - [STATUSES.STARTED]: { - icon: 'status-running', - text: __('Importing...'), - iconClass: 'gl-text-blue-400', - }, - [STATUSES.FINISHED]: { - icon: 'status-success', - text: __('Complete'), - iconClass: 'gl-text-green-400', - }, - [STATUSES.FAILED]: { - icon: 'status-failed', - text: __('Failed'), - iconClass: 'gl-text-red-600', - }, - [STATUSES.CANCELLED]: { - icon: 'status-stopped', - text: __('Cancelled'), - iconClass: 'gl-text-red-600', - }, -}; - -export default STATUS_MAP; diff --git a/app/assets/javascripts/import_entities/import_projects/components/provider_repo_table_row.vue b/app/assets/javascripts/import_entities/import_projects/components/provider_repo_table_row.vue index c3d0ca4ed8c..e4090a378e1 100644 --- a/app/assets/javascripts/import_entities/import_projects/components/provider_repo_table_row.vue +++ b/app/assets/javascripts/import_entities/import_projects/components/provider_repo_table_row.vue @@ -69,6 +69,10 @@ export default { return getImportStatus(this.repo); }, + stats() { + return this.repo.importedProject?.stats; + }, + importTarget() { return this.getImportTarget(this.repo.importSource.id); }, @@ -101,11 +105,11 @@ export default { - - + + - + { const repo = state.repositories.find((p) => p.importedProject?.id === updatedProject.id); if (repo?.importedProject) { - repo.importedProject.importStatus = updatedProject.importStatus; + repo.importedProject = { + ...repo.importedProject, + stats: updatedProject.stats, + importStatus: updatedProject.importStatus, + }; } }); }, diff --git a/app/assets/javascripts/jira_connect/subscriptions/components/app.vue b/app/assets/javascripts/jira_connect/subscriptions/components/app.vue index dfee70793eb..51db3e784aa 100644 --- a/app/assets/javascripts/jira_connect/subscriptions/components/app.vue +++ b/app/assets/javascripts/jira_connect/subscriptions/components/app.vue @@ -94,6 +94,7 @@ export default { v-if="shouldShowAlert" :variant="alert.variant" :title="alert.title" + class="gl-mb-5" data-testid="jira-connect-persisted-alert" @dismiss="setAlert" > diff --git a/app/assets/javascripts/jira_connect/subscriptions/components/subscriptions_list.vue b/app/assets/javascripts/jira_connect/subscriptions/components/subscriptions_list.vue index 33126040c16..0251728c896 100644 --- a/app/assets/javascripts/jira_connect/subscriptions/components/subscriptions_list.vue +++ b/app/assets/javascripts/jira_connect/subscriptions/components/subscriptions_list.vue @@ -1,5 +1,5 @@ - + diff --git a/app/assets/javascripts/search_settings/components/search_settings.vue b/app/assets/javascripts/search_settings/components/search_settings.vue index 3e23b8a3435..f6439c6f4c4 100644 --- a/app/assets/javascripts/search_settings/components/search_settings.vue +++ b/app/assets/javascripts/search_settings/components/search_settings.vue @@ -1,6 +1,6 @@ others.`; + const TEXT_CONTAIN_SEARCH_TERM = `This text contain ${SEARCH_TERM}.`; + const TEXT_WITH_SIBLING_ELEMENTS = `${SEARCH_TERM} Learn more.`; let wrapper; @@ -42,13 +44,7 @@ describe('search_settings/components/search_settings.vue', () => { }); }; - const matchParentElement = () => { - const highlightedList = Array.from(document.querySelectorAll(`.${HIGHLIGHT_CLASS}`)); - return highlightedList.map((element) => { - return element.parentNode; - }); - }; - + const findMatchSiblingElement = () => document.querySelector(`[data-testid="sibling"]`); const findSearchBox = () => wrapper.find(GlSearchBoxByType); const search = (term) => { findSearchBox().vm.$emit('input', term); @@ -56,7 +52,7 @@ describe('search_settings/components/search_settings.vue', () => { const clearSearch = () => search(''); beforeEach(() => { - setFixtures(` + setHTMLFixture(`
@@ -69,6 +65,7 @@ describe('search_settings/components/search_settings.vue', () => {
${SEARCH_TERM} ${TEXT_CONTAIN_SEARCH_TERM} + ${TEXT_WITH_SIBLING_ELEMENTS}
@@ -99,7 +96,7 @@ describe('search_settings/components/search_settings.vue', () => { it('highlight elements that match the search term', () => { search(SEARCH_TERM); - expect(highlightedElementsCount()).toBe(2); + expect(highlightedElementsCount()).toBe(3); }); it('highlight only search term and not the whole line', () => { @@ -108,14 +105,26 @@ describe('search_settings/components/search_settings.vue', () => { expect(highlightedTextNodes()).toBe(true); }); - it('prevents search xss', () => { + // Regression test for https://gitlab.com/gitlab-org/gitlab/-/issues/350494 + it('preserves elements that are siblings of matches', () => { + const snapshot = ` + + Learn more + + `; + + expect(findMatchSiblingElement()).toMatchInlineSnapshot(snapshot); + search(SEARCH_TERM); - const parentNodeList = matchParentElement(); - parentNodeList.forEach((element) => { - const scriptElement = element.getElementsByTagName('script'); - expect(scriptElement.length).toBe(0); - }); + expect(findMatchSiblingElement()).toMatchInlineSnapshot(snapshot); + + clearSearch(); + + expect(findMatchSiblingElement()).toMatchInlineSnapshot(snapshot); }); describe('default', () => { diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 1a1b92d3a9c..6e0c53a8823 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -6642,6 +6642,23 @@ RSpec.describe User do end end + describe '.without_forbidden_states' do + let_it_be(:normal_user) { create(:user, username: 'johndoe') } + let_it_be(:admin_user) { create(:user, :admin, username: 'iamadmin') } + let_it_be(:blocked_user) { create(:user, :blocked, username: 'notsorandom') } + let_it_be(:banned_user) { create(:user, :banned, username: 'iambanned') } + let_it_be(:external_user) { create(:user, :external) } + let_it_be(:unconfirmed_user) { create(:user, confirmed_at: nil) } + let_it_be(:omniauth_user) { create(:omniauth_user, provider: 'twitter', extern_uid: '123456') } + let_it_be(:internal_user) { User.alert_bot.tap { |u| u.confirm } } + + it 'does not return blocked, banned or unconfirmed users' do + expect(described_class.without_forbidden_states).to match_array([ + normal_user, admin_user, external_user, omniauth_user, internal_user + ]) + end + end + describe 'user_project' do it 'returns users project matched by username and public visibility' do user = create(:user) diff --git a/spec/requests/api/ci/secure_files_spec.rb b/spec/requests/api/ci/secure_files_spec.rb index 7e3060aa081..56838c4f6fd 100644 --- a/spec/requests/api/ci/secure_files_spec.rb +++ b/spec/requests/api/ci/secure_files_spec.rb @@ -257,22 +257,6 @@ RSpec.describe API::Ci::SecureFiles do expect(Base64.encode64(response.body)).to eq(Base64.encode64(fixture_file_upload('spec/fixtures/ci_secure_files/upload-keystore.jks').read)) end - it 'uploads and validates a secure file with a provided checksum' do - params = { - file: fixture_file_upload('spec/fixtures/ci_secure_files/upload-keystore.jks'), - name: 'upload-keystore.jks', - permissions: 'execute', - file_checksum: Digest::SHA256.hexdigest(File.read(fixture_file_upload('spec/fixtures/ci_secure_files/upload-keystore.jks'))) - } - - expect do - post api("/projects/#{project.id}/secure_files", maintainer), params: params - end.to change {project.secure_files.count}.by(1) - - expect(response).to have_gitlab_http_status(:created) - expect(json_response['name']).to eq('upload-keystore.jks') - end - it 'returns an error when the file checksum fails to validate' do secure_file.update!(checksum: 'foo') @@ -283,22 +267,6 @@ RSpec.describe API::Ci::SecureFiles do expect(response.code).to eq("500") end - it 'returns an error when the user provided file checksum fails to validate' do - post_params = { - file: fixture_file_upload('spec/fixtures/ci_secure_files/upload-keystore.jks'), - name: 'upload-keystore.jks', - permissions: 'read_write', - file_checksum: 'foo' - } - - expect do - post api("/projects/#{project.id}/secure_files", maintainer), params: post_params - end.not_to change { project.secure_files.count } - - expect(response).to have_gitlab_http_status(:bad_request) - expect(json_response['message']['file_checksum']).to include(_("Secure Files|File did not match the provided checksum")) - end - it 'returns an error when no file is uploaded' do post_params = { name: 'upload-keystore.jks' diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb index 518b0fd23c2..c554463df76 100644 --- a/spec/requests/api/users_spec.rb +++ b/spec/requests/api/users_spec.rb @@ -338,12 +338,14 @@ RSpec.describe API::Users do expect(response).to match_response_schema('public_api/v4/user/basics') expect(json_response.first.keys).not_to include 'is_admin' end + end + context "when admin" do context 'exclude_internal param' do let_it_be(:internal_user) { User.alert_bot } it 'returns all users when it is not set' do - get api("/users?exclude_internal=false", user) + get api("/users?exclude_internal=false", admin) expect(response).to match_response_schema('public_api/v4/user/basics') expect(response).to include_pagination_headers diff --git a/spec/support/shared_contexts/finders/users_finder_shared_contexts.rb b/spec/support/shared_contexts/finders/users_finder_shared_contexts.rb index 6a09497a497..ef1c01f72f9 100644 --- a/spec/support/shared_contexts/finders/users_finder_shared_contexts.rb +++ b/spec/support/shared_contexts/finders/users_finder_shared_contexts.rb @@ -3,8 +3,10 @@ RSpec.shared_context 'UsersFinder#execute filter by project context' do let_it_be(:normal_user) { create(:user, username: 'johndoe') } let_it_be(:admin_user) { create(:user, :admin, username: 'iamadmin') } + let_it_be(:banned_user) { create(:user, :banned, username: 'iambanned') } let_it_be(:blocked_user) { create(:user, :blocked, username: 'notsorandom') } let_it_be(:external_user) { create(:user, :external) } + let_it_be(:unconfirmed_user) { create(:user, confirmed_at: nil) } let_it_be(:omniauth_user) { create(:omniauth_user, provider: 'twitter', extern_uid: '123456') } - let_it_be(:internal_user) { User.alert_bot } + let_it_be(:internal_user) { User.alert_bot.tap { |u| u.confirm } } end