diff options
author | Jacob Vosmaer <jacob@gitlab.com> | 2018-05-30 17:05:23 +0200 |
---|---|---|
committer | Jacob Vosmaer <jacob@gitlab.com> | 2018-05-30 17:05:23 +0200 |
commit | dce000f65ed3cb27b815682cad623897e68776c5 (patch) | |
tree | 1b19217e748217ad75117c308ae5dbc0237e1cbd | |
parent | 1291d6a0cccf3a14db4c4d61a13943604bd792f4 (diff) | |
parent | 4e47fdb78e7cc1b961965496138bf0b16731f597 (diff) | |
download | gitlab-ce-gitaly-0.100.1-for-10-8-stable.tar.gz |
Merge branch '10-8-stable-patch-3' of https://gitlab.com/gitlab-org/gitlab-ce into gitaly-0.100.1-for-10-8-stablegitaly-0.100.1-for-10-8-stable
39 files changed, 445 insertions, 60 deletions
diff --git a/.gitignore b/.gitignore index c7d1648615d..51b77d5ac9e 100644 --- a/.gitignore +++ b/.gitignore @@ -64,6 +64,7 @@ eslint-report.html /tags /tmp/* /vendor/bundle/* +/vendor/gitaly-ruby /builds* /shared/* /.gitlab_workhorse_secret diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 05487134cb1..9c1eb2736b1 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -10,6 +10,7 @@ image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.3.7-golang-1.9-git paths: - vendor/ruby - .yarn-cache/ + - vendor/gitaly-ruby .push-cache: &push-cache cache: @@ -438,6 +439,7 @@ setup-test-env: paths: - tmp/tests - config/secrets.yml + - vendor/gitaly-ruby rspec-pg 0 28: *rspec-metadata-pg rspec-pg 1 28: *rspec-metadata-pg diff --git a/CHANGELOG.md b/CHANGELOG.md index 15730488819..c9950a51785 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,15 @@ documentation](doc/development/changelog.md) for instructions on adding your own entry. +## 10.8.2 (2018-05-28) + +### Security (3 changes) + +- Prevent user passwords from being changed without providing the previous password. +- Fix API to remove deploy key from project instead of deleting it entirely. +- Fixed bug that allowed importing arbitrary project attributes. + + ## 10.8.1 (2018-05-23) ### Fixed (9 changes) diff --git a/GITLAB_WORKHORSE_VERSION b/GITLAB_WORKHORSE_VERSION index 6aba2b245a8..fae6e3d04b2 100644 --- a/GITLAB_WORKHORSE_VERSION +++ b/GITLAB_WORKHORSE_VERSION @@ -1 +1 @@ -4.2.0 +4.2.1 diff --git a/Gemfile.lock b/Gemfile.lock index d2f7c6fdae5..ffcf3db13c9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -811,7 +811,7 @@ GEM rubyzip (1.2.1) rufus-scheduler (3.4.0) et-orbi (~> 1.0) - rugged (0.27.0) + rugged (0.27.1) safe_yaml (1.0.4) sanitize (2.1.0) nokogiri (>= 1.4.4) @@ -940,7 +940,7 @@ GEM unf (0.1.4) unf_ext unf_ext (0.0.7.5) - unicode-display_width (1.3.0) + unicode-display_width (1.3.2) unicorn (5.1.0) kgio (~> 2.6) raindrops (~> 0.7) @@ -1 +1 @@ -10.8.1 +10.8.2 diff --git a/app/assets/javascripts/compare_autocomplete.js b/app/assets/javascripts/compare_autocomplete.js index 9c88466e576..15cdc751570 100644 --- a/app/assets/javascripts/compare_autocomplete.js +++ b/app/assets/javascripts/compare_autocomplete.js @@ -54,7 +54,7 @@ export default function initCompareAutocomplete(limitTo = null, clickHandler = ( .attr('href', '#') .addClass(ref === selected ? 'is-active' : '') .text(ref) - .attr('data-ref', escape(ref)); + .attr('data-ref', ref); return $('<li />').append(link); } }, diff --git a/app/assets/javascripts/issuable_form.js b/app/assets/javascripts/issuable_form.js index 90d4e19e90b..bb8b3d91e40 100644 --- a/app/assets/javascripts/issuable_form.js +++ b/app/assets/javascripts/issuable_form.js @@ -30,7 +30,7 @@ export default class IssuableForm { } this.initAutosave(); - this.form.on('submit:success', this.handleSubmit); + this.form.on('submit', this.handleSubmit); this.form.on('click', '.btn-cancel', this.resetAutosave); this.initWip(); diff --git a/app/controllers/profiles_controller.rb b/app/controllers/profiles_controller.rb index ac71f72e624..9f5ad23a20f 100644 --- a/app/controllers/profiles_controller.rb +++ b/app/controllers/profiles_controller.rb @@ -93,8 +93,6 @@ class ProfilesController < Profiles::ApplicationController :linkedin, :location, :name, - :password, - :password_confirmation, :public_email, :skype, :twitter, diff --git a/changelogs/unreleased/ensure-remote-mirror-columns-in-ce.yml b/changelogs/unreleased/ensure-remote-mirror-columns-in-ce.yml new file mode 100644 index 00000000000..7617412431f --- /dev/null +++ b/changelogs/unreleased/ensure-remote-mirror-columns-in-ce.yml @@ -0,0 +1,5 @@ +--- +title: Fix remote mirror database inconsistencies when upgrading from EE to CE +merge_request: 19196 +author: +type: fixed diff --git a/changelogs/unreleased/memoize-database-version.yml b/changelogs/unreleased/memoize-database-version.yml new file mode 100644 index 00000000000..575348a53a1 --- /dev/null +++ b/changelogs/unreleased/memoize-database-version.yml @@ -0,0 +1,5 @@ +--- +title: Memoize Gitlab::Database.version +merge_request: +author: +type: performance diff --git a/changelogs/unreleased/sh-fix-submit-not-clearing-local-storage.yml b/changelogs/unreleased/sh-fix-submit-not-clearing-local-storage.yml new file mode 100644 index 00000000000..422143aa5e6 --- /dev/null +++ b/changelogs/unreleased/sh-fix-submit-not-clearing-local-storage.yml @@ -0,0 +1,5 @@ +--- +title: Fix local storage not being cleared after creating a new issue +merge_request: +author: +type: fixed diff --git a/changelogs/unreleased/winh-new-merge-request-encoding.yml b/changelogs/unreleased/winh-new-merge-request-encoding.yml new file mode 100644 index 00000000000..f797657e660 --- /dev/null +++ b/changelogs/unreleased/winh-new-merge-request-encoding.yml @@ -0,0 +1,5 @@ +--- +title: Fix encoding of branch names on compare and new merge request page +merge_request: 19143 +author: +type: fixed diff --git a/db/migrate/20180529093006_ensure_remote_mirror_columns.rb b/db/migrate/20180529093006_ensure_remote_mirror_columns.rb new file mode 100644 index 00000000000..290416cb61c --- /dev/null +++ b/db/migrate/20180529093006_ensure_remote_mirror_columns.rb @@ -0,0 +1,24 @@ +class EnsureRemoteMirrorColumns < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + def up + add_column :remote_mirrors, :last_update_started_at, :datetime unless column_exists?(:remote_mirrors, :last_update_started_at) + add_column :remote_mirrors, :remote_name, :string unless column_exists?(:remote_mirrors, :remote_name) + + unless column_exists?(:remote_mirrors, :only_protected_branches) + add_column_with_default(:remote_mirrors, + :only_protected_branches, + :boolean, + default: false, + allow_null: false) + end + end + + def down + # db/migrate/20180503131624_create_remote_mirrors.rb will remove the table + end +end diff --git a/db/schema.rb b/db/schema.rb index 168ab198025..393114e3a3c 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20180508102840) do +ActiveRecord::Schema.define(version: 20180529093006) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" diff --git a/doc/user/snippets.md b/doc/user/snippets.md index 2170b079f62..8397c0b00ef 100644 --- a/doc/user/snippets.md +++ b/doc/user/snippets.md @@ -27,3 +27,36 @@ Personal snippets are not related to any project and can be created completely i You can download the raw content of a snippet. By default snippets will be downloaded with Linux-style line endings (`LF`). If you want to preserve the original line endings you need to add a parameter `line_ending=raw` (eg. `https://gitlab.com/snippets/SNIPPET_ID/raw?line_ending=raw`). In case a snippet was created using the GitLab web interface the original line ending is Windows-like (`CRLF`). + +## Embedded Snippets + +> Introduced in GitLab 10.8. + +Public snippets can not only be shared, but also embedded on any website. This +allows to reuse a GitLab snippet in multiple places and any change to the source +is automatically reflected in the embedded snippet. + +To embed a snippet, first make sure that: + +- The project is public (if it's a project snippet) +- The snippet is public +- In **Project > Settings > Permissions**, the snippets permissions are + set to **Everyone with access** + +Once the above conditions are met, the "Embed" section will appear in your snippet +where you can simply click on the "Copy to clipboard" button. This copies a one-line +script that you can add to any website or blog post. + +Here's how an example code looks like: + +```html +<script src="https://gitlab.com/namespace/project/snippets/SNIPPET_ID.js"></script> +``` + +Here's how an embedded snippet looks like: + +<script src="https://gitlab.com/gitlab-org/gitlab-ce/snippets/1717978.js"></script> + +Embedded snippets are displayed with a header that shows the file name if defined, +the snippet size, a link to GitLab, and the actual snippet content. Actions in +the header allow users to see the snippet in raw format and download it. diff --git a/lib/api/deploy_keys.rb b/lib/api/deploy_keys.rb index 70d43ac1d79..b7aadc27e71 100644 --- a/lib/api/deploy_keys.rb +++ b/lib/api/deploy_keys.rb @@ -148,10 +148,10 @@ module API requires :key_id, type: Integer, desc: 'The ID of the deploy key' end delete ":id/deploy_keys/:key_id" do - key = user_project.deploy_keys.find(params[:key_id]) - not_found!('Deploy Key') unless key + deploy_key_project = user_project.deploy_keys_projects.find_by(deploy_key_id: params[:key_id]) + not_found!('Deploy Key') unless deploy_key_project - destroy_conditionally!(key) + destroy_conditionally!(deploy_key_project) end end end diff --git a/lib/gitlab/database.rb b/lib/gitlab/database.rb index 76501dd50e8..d49d055c3f2 100644 --- a/lib/gitlab/database.rb +++ b/lib/gitlab/database.rb @@ -43,7 +43,7 @@ module Gitlab end def self.version - database_version.match(/\A(?:PostgreSQL |)([^\s]+).*\z/)[1] + @version ||= database_version.match(/\A(?:PostgreSQL |)([^\s]+).*\z/)[1] end def self.join_lateral_supported? diff --git a/lib/gitlab/import_export/attribute_cleaner.rb b/lib/gitlab/import_export/attribute_cleaner.rb index 34169319b26..7c9fc5c15bb 100644 --- a/lib/gitlab/import_export/attribute_cleaner.rb +++ b/lib/gitlab/import_export/attribute_cleaner.rb @@ -7,14 +7,15 @@ module Gitlab new(*args).clean end - def initialize(relation_hash:, relation_class:) + def initialize(relation_hash:, relation_class:, excluded_keys: []) @relation_hash = relation_hash @relation_class = relation_class + @excluded_keys = excluded_keys end def clean @relation_hash.reject do |key, _value| - prohibited_key?(key) || !@relation_class.attribute_method?(key) + prohibited_key?(key) || !@relation_class.attribute_method?(key) || excluded_key?(key) end.except('id') end @@ -23,6 +24,12 @@ module Gitlab def prohibited_key?(key) key.end_with?('_id') && !ALLOWED_REFERENCES.include?(key) end + + def excluded_key?(key) + return false if @excluded_keys.empty? + + @excluded_keys.include?(key) + end end end end diff --git a/lib/gitlab/import_export/attributes_finder.rb b/lib/gitlab/import_export/attributes_finder.rb index 56042ddecbf..0c8fda07294 100644 --- a/lib/gitlab/import_export/attributes_finder.rb +++ b/lib/gitlab/import_export/attributes_finder.rb @@ -32,6 +32,10 @@ module Gitlab @methods[key].nil? ? {} : { methods: @methods[key] } end + def find_excluded_keys(klass_name) + @excluded_attributes[klass_name.to_sym]&.map(&:to_s) || [] + end + private def find_attributes_only(value) diff --git a/lib/gitlab/import_export/import_export.yml b/lib/gitlab/import_export/import_export.yml index 21ac7f7e0b6..36c7534cd7a 100644 --- a/lib/gitlab/import_export/import_export.yml +++ b/lib/gitlab/import_export/import_export.yml @@ -98,8 +98,6 @@ excluded_attributes: - :import_jid - :created_at - :updated_at - - :import_jid - - :import_jid - :id - :star_count - :last_activity_at diff --git a/lib/gitlab/import_export/project_tree_restorer.rb b/lib/gitlab/import_export/project_tree_restorer.rb index d5590dde40f..4eb67fbe11e 100644 --- a/lib/gitlab/import_export/project_tree_restorer.rb +++ b/lib/gitlab/import_export/project_tree_restorer.rb @@ -88,16 +88,18 @@ module Gitlab end def project_params - @project_params ||= json_params.merge(override_params) + @project_params ||= begin + attrs = json_params.merge(override_params) + + # Cleaning all imported and overridden params + Gitlab::ImportExport::AttributeCleaner.clean(relation_hash: attrs, + relation_class: Project, + excluded_keys: excluded_keys_for_relation(:project)) + end end def override_params - return {} unless params = @project.import_data&.data&.fetch('override_params', nil) - - @override_params ||= params.select do |key, _value| - Project.column_names.include?(key.to_s) && - !reader.project_tree[:except].include?(key.to_sym) - end + @override_params ||= @project.import_data&.data&.fetch('override_params', nil) || {} end def json_params @@ -171,7 +173,8 @@ module Gitlab relation_hash: parsed_relation_hash(relation_hash, relation.to_sym), members_mapper: members_mapper, user: @user, - project: @restored_project) + project: @restored_project, + excluded_keys: excluded_keys_for_relation(relation)) end.compact relation_hash_list.is_a?(Array) ? relation_array : relation_array.first @@ -192,6 +195,10 @@ module Gitlab def reader @reader ||= Gitlab::ImportExport::Reader.new(shared: @shared) end + + def excluded_keys_for_relation(relation) + @reader.attributes_finder.find_excluded_keys(relation) + end end end end diff --git a/lib/gitlab/import_export/reader.rb b/lib/gitlab/import_export/reader.rb index eb7f5120592..e621c40fc7a 100644 --- a/lib/gitlab/import_export/reader.rb +++ b/lib/gitlab/import_export/reader.rb @@ -1,7 +1,7 @@ module Gitlab module ImportExport class Reader - attr_reader :tree + attr_reader :tree, :attributes_finder def initialize(shared:) @shared = shared diff --git a/lib/gitlab/import_export/relation_factory.rb b/lib/gitlab/import_export/relation_factory.rb index e3e9f156fb4..301719406e4 100644 --- a/lib/gitlab/import_export/relation_factory.rb +++ b/lib/gitlab/import_export/relation_factory.rb @@ -36,13 +36,21 @@ module Gitlab new(*args).create end - def initialize(relation_sym:, relation_hash:, members_mapper:, user:, project:) + def initialize(relation_sym:, relation_hash:, members_mapper:, user:, project:, excluded_keys: []) @relation_name = OVERRIDES[relation_sym] || relation_sym @relation_hash = relation_hash.except('noteable_id') @members_mapper = members_mapper @user = user @project = project @imported_object_retries = 0 + + # Remove excluded keys from relation_hash + # We don't do this in the parsed_relation_hash because of the 'transformed attributes' + # For example, MergeRequestDiffFiles exports its diff attribute as utf8_diff. Then, + # in the create method that attribute is renamed to diff. And because diff is an excluded key, + # if we clean the excluded keys in the parsed_relation_hash, it will be removed + # from the object attributes and the export will fail. + @relation_hash.except!(*excluded_keys) end # Creates an object from an actual model with name "relation_sym" with params from diff --git a/scripts/gitaly-test-build b/scripts/gitaly-test-build index b42ae2a2595..374401caf89 100755 --- a/scripts/gitaly-test-build +++ b/scripts/gitaly-test-build @@ -2,28 +2,29 @@ require 'fileutils' +require_relative 'gitaly_test' + # This script assumes tmp/tests/gitaly already contains the correct # Gitaly version. We just have to compile it and run its 'bundle -# install'. We have this separate script for that because weird things -# were happening in CI when we have a 'bundle exec' process that later -# called 'bundle install' using a different Gemfile, as happens with -# gitlab-ce and gitaly. +# install'. We have this separate script for that to avoid bundle +# poisoning in CI. This script should only be run in CI. +class GitalyTestBuild + include GitalyTest -tmp_tests_gitaly_dir = File.expand_path('../tmp/tests/gitaly', __dir__) + def run + abort 'gitaly build failed' unless system(env, 'make', chdir: tmp_tests_gitaly_dir) -# Use the top-level bundle vendor folder so that we don't reinstall gems twice -bundle_vendor_path = File.expand_path('../vendor', __dir__) + check_gitaly_config! -env = { - # This ensure the `clean` config set in `scripts/prepare_build.sh` isn't taken into account - 'BUNDLE_IGNORE_CONFIG' => 'true', - 'BUNDLE_GEMFILE' => File.join(tmp_tests_gitaly_dir, 'ruby', 'Gemfile'), - 'BUNDLE_FLAGS' => "--jobs=4 --path=#{bundle_vendor_path} --retry=3" -} + # Starting gitaly further validates its configuration + pid = start_gitaly + Process.kill('TERM', pid) -abort 'gitaly build failed' unless system(env, 'make', chdir: tmp_tests_gitaly_dir) + # Make the 'gitaly' executable look newer than 'GITALY_SERVER_VERSION'. + # Without this a gitaly executable created in the setup-test-env job + # will look stale compared to GITALY_SERVER_VERSION. + FileUtils.touch(File.join(tmp_tests_gitaly_dir, 'gitaly'), mtime: Time.now + (1 << 24)) + end +end -# Make the 'gitaly' executable look newer than 'GITALY_SERVER_VERSION'. -# Without this a gitaly executable created in the setup-test-env job -# will look stale compared to GITALY_SERVER_VERSION. -FileUtils.touch(File.join(tmp_tests_gitaly_dir, 'gitaly'), mtime: Time.now + (1 << 24)) +GitalyTestBuild.new.run diff --git a/scripts/gitaly-test-spawn b/scripts/gitaly-test-spawn index ecb68c6acc6..e9f91f75650 100755 --- a/scripts/gitaly-test-spawn +++ b/scripts/gitaly-test-spawn @@ -1,9 +1,23 @@ #!/usr/bin/env ruby -gitaly_dir = 'tmp/tests/gitaly' -env = { 'HOME' => File.expand_path('tmp/tests'), - 'GEM_PATH' => Gem.path.join(':') } -args = %W[#{gitaly_dir}/gitaly #{gitaly_dir}/config.toml] +# This script is used both in CI and in local development 'rspec' runs. -# Print the PID of the spawned process -puts spawn(env, *args, [:out, :err] => 'log/gitaly-test.log') +require_relative 'gitaly_test' + +class GitalyTestSpawn + include GitalyTest + + def run + check_gitaly_config! + + # # Uncomment line below to see all gitaly logs merged into CI trace + # spawn('sleep 1; tail -f log/gitaly-test.log') + + pid = start_gitaly + + # In local development this pid file is used by rspec. + IO.write(File.expand_path('../tmp/tests/gitaly.pid', __dir__), pid) + end +end + +GitalyTestSpawn.new.run diff --git a/scripts/gitaly_test.rb b/scripts/gitaly_test.rb new file mode 100644 index 00000000000..dee4c2eba7e --- /dev/null +++ b/scripts/gitaly_test.rb @@ -0,0 +1,97 @@ +# This file contains environment settings for gitaly when it's running +# as part of the gitlab-ce/ee test suite. +# +# Please be careful when modifying this file. Your changes must work +# both for local development rspec runs, and in CI. + +require 'socket' + +module GitalyTest + def tmp_tests_gitaly_dir + File.expand_path('../tmp/tests/gitaly', __dir__) + end + + def gemfile + File.join(tmp_tests_gitaly_dir, 'ruby', 'Gemfile') + end + + def env + env_hash = { + 'HOME' => File.expand_path('tmp/tests'), + 'GEM_PATH' => Gem.path.join(':'), + 'BUNDLE_APP_CONFIG' => File.join(File.dirname(gemfile), '.bundle/config'), + 'BUNDLE_FLAGS' => "--jobs=4 --retry=3", + 'BUNDLE_INSTALL_FLAGS' => nil, + 'BUNDLE_GEMFILE' => gemfile, + 'RUBYOPT' => nil + } + + if ENV['CI'] + bundle_path = File.expand_path('../vendor/gitaly-ruby', __dir__) + env_hash['BUNDLE_FLAGS'] << " --path=#{bundle_path}" + end + + env_hash + end + + def config_path + File.join(tmp_tests_gitaly_dir, 'config.toml') + end + + def start_gitaly + args = %W[#{tmp_tests_gitaly_dir}/gitaly #{config_path}] + pid = spawn(env, *args, [:out, :err] => 'log/gitaly-test.log') + + begin + try_connect! + rescue + Process.kill('TERM', pid) + raise + end + + pid + end + + def check_gitaly_config! + puts 'Checking gitaly-ruby bundle...' + abort 'bundle check failed' unless system(env, 'bundle', 'check', chdir: File.dirname(gemfile)) + end + + def read_socket_path + # This code needs to work in an environment where we cannot use bundler, + # so we cannot easily use the toml-rb gem. This ad-hoc parser should be + # good enough. + config_text = IO.read(config_path) + + config_text.lines.each do |line| + match_data = line.match(/^\s*socket_path\s*=\s*"([^"]*)"$/) + + return match_data[1] if match_data + end + + raise "failed to find socket_path in #{config_path}" + end + + def try_connect! + print "Trying to connect to gitaly: " + timeout = 20 + delay = 0.1 + socket = read_socket_path + + Integer(timeout / delay).times do + begin + UNIXSocket.new(socket) + puts ' OK' + + return + rescue Errno::ENOENT, Errno::ECONNREFUSED + print '.' + sleep delay + end + end + + puts ' FAILED' + + raise "could not connect to #{socket}" + end +end diff --git a/spec/controllers/profiles_controller_spec.rb b/spec/controllers/profiles_controller_spec.rb index c621eb69171..35b42be2e3d 100644 --- a/spec/controllers/profiles_controller_spec.rb +++ b/spec/controllers/profiles_controller_spec.rb @@ -3,6 +3,19 @@ require('spec_helper') describe ProfilesController, :request_store do let(:user) { create(:user) } + describe 'POST update' do + it 'does not update password' do + sign_in(user) + + expect do + post :update, + user: { password: 'hello12345', password_confirmation: 'hello12345' } + end.not_to change { user.reload.encrypted_password } + + expect(response.status).to eq(302) + end + end + describe 'PUT update' do it 'allows an email update from a user without an external email address' do sign_in(user) diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb index 314bd19f586..b677d01fdf9 100644 --- a/spec/features/issues_spec.rb +++ b/spec/features/issues_spec.rb @@ -591,6 +591,20 @@ describe 'Issues' do end end + it 'clears local storage after creating a new issue', :js do + 2.times.each do + visit new_project_issue_path(project) + wait_for_requests + + expect(page).to have_field('Title', with: '') + + fill_in 'issue_title', with: 'bug 345' + fill_in 'issue_description', with: 'bug description' + + click_button 'Submit issue' + end + end + context 'dropzone upload file', :js do before do visit new_project_issue_path(project) diff --git a/spec/features/merge_request/user_selects_branches_for_new_mr_spec.rb b/spec/features/merge_request/user_selects_branches_for_new_mr_spec.rb index 42c279af117..ed6e29335d1 100644 --- a/spec/features/merge_request/user_selects_branches_for_new_mr_spec.rb +++ b/spec/features/merge_request/user_selects_branches_for_new_mr_spec.rb @@ -4,6 +4,12 @@ describe 'Merge request > User selects branches for new MR', :js do let(:project) { create(:project, :public, :repository) } let(:user) { project.creator } + def select_source_branch(branch_name) + find('.js-source-branch', match: :first).click + find('.js-source-branch-dropdown .dropdown-input-field').native.send_keys branch_name + find('.js-source-branch-dropdown .dropdown-content a', text: branch_name, match: :first).click + end + before do project.add_master(user) sign_in(user) @@ -43,8 +49,7 @@ describe 'Merge request > User selects branches for new MR', :js do it 'generates a diff for an orphaned branch' do visit project_new_merge_request_path(project) - find('.js-source-branch', match: :first).click - find('.js-source-branch-dropdown .dropdown-content a', text: 'orphaned-branch', match: :first).click + select_source_branch('orphaned-branch') click_button "Compare branches" click_link "Changes" @@ -169,4 +174,31 @@ describe 'Merge request > User selects branches for new MR', :js do end end end + + context 'with special characters in branch names' do + it 'escapes quotes in branch names' do + special_branch_name = '"with-quotes"' + CreateBranchService.new(project, user) + .execute(special_branch_name, 'add-pdf-file') + + visit project_new_merge_request_path(project) + select_source_branch(special_branch_name) + + source_branch_input = find('[name="merge_request[source_branch]"]', visible: false) + expect(source_branch_input.value).to eq special_branch_name + end + + it 'does not escape unicode in branch names' do + special_branch_name = 'ʕ•ᴥ•ʔ' + CreateBranchService.new(project, user) + .execute(special_branch_name, 'add-pdf-file') + + visit project_new_merge_request_path(project) + select_source_branch(special_branch_name) + + click_button "Compare branches" + + expect(page).to have_button("Submit merge request") + end + end end diff --git a/spec/features/users/terms_spec.rb b/spec/features/users/terms_spec.rb index f9469adbfe3..1efa5cd5490 100644 --- a/spec/features/users/terms_spec.rb +++ b/spec/features/users/terms_spec.rb @@ -62,7 +62,8 @@ describe 'Users > Terms' do expect(current_path).to eq(project_issues_path(project)) end - it 'redirects back to the page the user was trying to save' do + # Disabled until https://gitlab.com/gitlab-org/gitlab-ce/issues/37162 is solved properly + xit 'redirects back to the page the user was trying to save' do visit new_project_issue_path(project) fill_in :issue_title, with: 'Hello world, a new issue' diff --git a/spec/lib/gitlab/database_spec.rb b/spec/lib/gitlab/database_spec.rb index 1fe1d3926ad..8ac36ae8bab 100644 --- a/spec/lib/gitlab/database_spec.rb +++ b/spec/lib/gitlab/database_spec.rb @@ -32,6 +32,12 @@ describe Gitlab::Database do end describe '.version' do + around do |example| + described_class.instance_variable_set(:@version, nil) + example.run + described_class.instance_variable_set(:@version, nil) + end + context "on mysql" do it "extracts the version number" do allow(described_class).to receive(:database_version) @@ -49,6 +55,14 @@ describe Gitlab::Database do expect(described_class.version).to eq '9.4.4' end end + + it 'memoizes the result' do + count = ActiveRecord::QueryRecorder + .new { 2.times { described_class.version } } + .count + + expect(count).to eq(1) + end end describe '.join_lateral_supported?' do diff --git a/spec/lib/gitlab/import_export/attribute_cleaner_spec.rb b/spec/lib/gitlab/import_export/attribute_cleaner_spec.rb index cd5a1b2982b..536cc359d39 100644 --- a/spec/lib/gitlab/import_export/attribute_cleaner_spec.rb +++ b/spec/lib/gitlab/import_export/attribute_cleaner_spec.rb @@ -15,7 +15,10 @@ describe Gitlab::ImportExport::AttributeCleaner do 'project_id' => 99, 'user_id' => 99, 'random_id_in_the_middle' => 99, - 'notid' => 99 + 'notid' => 99, + 'import_source' => 'whatever', + 'import_type' => 'whatever', + 'non_existent_attr' => 'whatever' } end @@ -28,10 +31,30 @@ describe Gitlab::ImportExport::AttributeCleaner do } end + let(:excluded_keys) { %w[import_source import_type] } + + subject { described_class.clean(relation_hash: unsafe_hash, relation_class: relation_class, excluded_keys: excluded_keys) } + + before do + allow(relation_class).to receive(:attribute_method?).and_return(true) + allow(relation_class).to receive(:attribute_method?).with('non_existent_attr').and_return(false) + end + it 'removes unwanted attributes from the hash' do - # allow(relation_class).to receive(:attribute_method?).and_return(true) + expect(subject).to eq(post_safe_hash) + end + + it 'removes attributes not present in relation_class' do + expect(subject.keys).not_to include 'non_existent_attr' + end + + it 'removes excluded keys from the hash' do + expect(subject.keys).not_to include excluded_keys + end + + it 'does not remove excluded key if not listed' do parsed_hash = described_class.clean(relation_hash: unsafe_hash, relation_class: relation_class) - expect(parsed_hash).to eq(post_safe_hash) + expect(parsed_hash.keys).to eq post_safe_hash.keys + excluded_keys end end diff --git a/spec/lib/gitlab/import_export/project.json b/spec/lib/gitlab/import_export/project.json index 6d63749296e..4d0cc1f196e 100644 --- a/spec/lib/gitlab/import_export/project.json +++ b/spec/lib/gitlab/import_export/project.json @@ -1,5 +1,7 @@ { "description": "Nisi et repellendus ut enim quo accusamus vel magnam.", + "import_type": "gitlab_project", + "creator_id": 123, "visibility_level": 10, "archived": false, "labels": [ diff --git a/spec/lib/gitlab/import_export/project.light.json b/spec/lib/gitlab/import_export/project.light.json index 5dbf0ed289b..c13cf4a0507 100644 --- a/spec/lib/gitlab/import_export/project.light.json +++ b/spec/lib/gitlab/import_export/project.light.json @@ -1,5 +1,7 @@ { "description": "Nisi et repellendus ut enim quo accusamus vel magnam.", + "import_type": "gitlab_project", + "creator_id": 123, "visibility_level": 10, "archived": false, "milestones": [ diff --git a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb index 13a8c9adcee..68ddc947e02 100644 --- a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb +++ b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb @@ -23,6 +23,10 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do allow_any_instance_of(Gitlab::Git::Repository).to receive(:create_branch) project_tree_restorer = described_class.new(user: @user, shared: @shared, project: @project) + + expect(Gitlab::ImportExport::RelationFactory).to receive(:create).with(hash_including(excluded_keys: ['whatever'])).and_call_original.at_least(:once) + allow(project_tree_restorer).to receive(:excluded_keys_for_relation).and_return(['whatever']) + @restored_project_json = project_tree_restorer.restore end end @@ -248,6 +252,11 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do expect(labels.where(type: "ProjectLabel").count).to eq(results.fetch(:first_issue_labels, 0)) expect(labels.where(type: "ProjectLabel").where.not(group_id: nil).count).to eq(0) end + + it 'does not set params that are excluded from import_export settings' do + expect(project.import_type).to be_nil + expect(project.creator_id).not_to eq 123 + end end shared_examples 'restores group correctly' do |**results| diff --git a/spec/lib/gitlab/import_export/relation_factory_spec.rb b/spec/lib/gitlab/import_export/relation_factory_spec.rb index 5c61a5a2044..5f0dfd64b15 100644 --- a/spec/lib/gitlab/import_export/relation_factory_spec.rb +++ b/spec/lib/gitlab/import_export/relation_factory_spec.rb @@ -4,12 +4,14 @@ describe Gitlab::ImportExport::RelationFactory do let(:project) { create(:project) } let(:members_mapper) { double('members_mapper').as_null_object } let(:user) { create(:admin) } + let(:excluded_keys) { [] } let(:created_object) do described_class.create(relation_sym: relation_sym, relation_hash: relation_hash, members_mapper: members_mapper, user: user, - project: project) + project: project, + excluded_keys: excluded_keys) end context 'hook object' do @@ -67,6 +69,14 @@ describe Gitlab::ImportExport::RelationFactory do expect(created_object.service_id).not_to eq(service_id) end end + + context 'excluded attributes' do + let(:excluded_keys) { %w[url] } + + it 'are removed from the imported object' do + expect(created_object.url).to be_nil + end + end end # Mocks an ActiveRecordish object with the dodgy columns diff --git a/spec/requests/api/deploy_keys_spec.rb b/spec/requests/api/deploy_keys_spec.rb index ae9c0e9c304..32fc704a79b 100644 --- a/spec/requests/api/deploy_keys_spec.rb +++ b/spec/requests/api/deploy_keys_spec.rb @@ -171,7 +171,7 @@ describe API::DeployKeys do deploy_key end - it 'deletes existing key' do + it 'removes existing key from project' do expect do delete api("/projects/#{project.id}/deploy_keys/#{deploy_key.id}", admin) @@ -179,6 +179,44 @@ describe API::DeployKeys do end.to change { project.deploy_keys.count }.by(-1) end + context 'when the deploy key is public' do + it 'does not delete the deploy key' do + expect do + delete api("/projects/#{project.id}/deploy_keys/#{deploy_key.id}", admin) + + expect(response).to have_gitlab_http_status(204) + end.not_to change { DeployKey.count } + end + end + + context 'when the deploy key is not public' do + let!(:deploy_key) { create(:deploy_key, public: false) } + + context 'when the deploy key is only used by this project' do + it 'deletes the deploy key' do + expect do + delete api("/projects/#{project.id}/deploy_keys/#{deploy_key.id}", admin) + + expect(response).to have_gitlab_http_status(204) + end.to change { DeployKey.count }.by(-1) + end + end + + context 'when the deploy key is used by other projects' do + before do + create(:deploy_keys_project, project: project2, deploy_key: deploy_key) + end + + it 'does not delete the deploy key' do + expect do + delete api("/projects/#{project.id}/deploy_keys/#{deploy_key.id}", admin) + + expect(response).to have_gitlab_http_status(204) + end.not_to change { DeployKey.count } + end + end + end + it 'returns 404 Not Found with invalid ID' do delete api("/projects/#{project.id}/deploy_keys/404", admin) diff --git a/spec/support/helpers/test_env.rb b/spec/support/helpers/test_env.rb index 1dad39fdab3..57aa07cf4fa 100644 --- a/spec/support/helpers/test_env.rb +++ b/spec/support/helpers/test_env.rb @@ -159,7 +159,11 @@ module TestEnv end spawn_script = Rails.root.join('scripts/gitaly-test-spawn').to_s - @gitaly_pid = Bundler.with_original_env { IO.popen([spawn_script], &:read).to_i } + Bundler.with_original_env do + raise "gitaly spawn failed" unless system(spawn_script) + end + @gitaly_pid = Integer(File.read('tmp/tests/gitaly.pid')) + Kernel.at_exit { stop_gitaly } wait_gitaly |