summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Release Tools Bot <delivery-team+release-tools@gitlab.com>2021-08-31 17:33:50 +0000
committerGitLab Release Tools Bot <delivery-team+release-tools@gitlab.com>2021-08-31 17:33:50 +0000
commit4a7ac19f2777913bbd7152aa08395411b5fe05c3 (patch)
treeb2cd2eec1d5c64c5a8f07c125e7f500fd9cb6761
parent132256d76b139f131cd2a769d40f9189208bf1ae (diff)
parent5890651c606d31f3365c203fe107dcaa7296ef2b (diff)
downloadgitlab-ce-4a7ac19f2777913bbd7152aa08395411b5fe05c3.tar.gz
Merge remote-tracking branch 'dev/14-1-stable' into 14-1-stable
-rw-r--r--CHANGELOG.md13
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--Gemfile2
-rw-r--r--Gemfile.lock6
-rw-r--r--VERSION2
-rw-r--r--app/controllers/jira_connect/app_descriptor_controller.rb12
-rw-r--r--app/controllers/jira_connect/application_controller.rb24
-rw-r--r--app/controllers/jira_connect/subscriptions_controller.rb6
-rw-r--r--app/controllers/users_controller.rb7
-rw-r--r--app/helpers/integrations_helper.rb2
-rw-r--r--app/models/design_management/design.rb2
-rw-r--r--app/models/integrations/datadog.rb9
-rw-r--r--app/models/jira_connect_installation.rb4
-rw-r--r--app/services/groups/destroy_service.rb35
-rw-r--r--app/services/jira_connect_subscriptions/create_service.rb7
-rw-r--r--app/services/resource_access_tokens/create_service.rb2
-rw-r--r--config/initializers/apollo_upload_server.rb5
-rw-r--r--db/post_migrate/20210811122206_update_external_project_bots.rb33
-rw-r--r--db/schema_migrations/202108111222061
-rw-r--r--doc/development/import_export.md2
-rw-r--r--doc/integration/jira/connect-app.md7
-rw-r--r--doc/user/project/settings/import_export.md2
-rw-r--r--lib/atlassian/jira_connect/client.rb20
-rw-r--r--lib/atlassian/jira_connect/jira_user.rb18
-rw-r--r--lib/gitlab/import_export/group/import_export.yml2
-rw-r--r--lib/gitlab/import_export/group/legacy_import_export.yml2
-rw-r--r--lib/gitlab/import_export/members_mapper.rb7
-rw-r--r--lib/gitlab/import_export/project/import_export.yml2
-rw-r--r--lib/gitlab/markdown_cache.rb2
-rw-r--r--lib/gitlab/middleware/multipart.rb2
-rw-r--r--spec/controllers/jira_connect/subscriptions_controller_spec.rb37
-rw-r--r--spec/features/file_uploads/graphql_add_design_spec.rb12
-rw-r--r--spec/fixtures/group.json2
-rw-r--r--spec/fixtures/lib/gitlab/import_export/complex/project.json8
-rw-r--r--spec/fixtures/lib/gitlab/import_export/complex/tree/project/project_members.ndjson8
-rw-r--r--spec/fixtures/lib/gitlab/import_export/designs/project.json4
-rw-r--r--spec/fixtures/lib/gitlab/import_export/group_exports/complex/group.json36
-rw-r--r--spec/fixtures/lib/gitlab/import_export/group_exports/complex/tree/groups/4351/members.ndjson12
-rw-r--r--spec/fixtures/lib/gitlab/import_export/group_exports/complex/tree/groups/4352/members.ndjson12
-rw-r--r--spec/fixtures/lib/gitlab/import_export/group_exports/complex/tree/groups/4353/members.ndjson12
-rw-r--r--spec/fixtures/lib/gitlab/import_export/group_exports/no_children/group.json12
-rw-r--r--spec/fixtures/lib/gitlab/import_export/group_exports/no_children/tree/groups/4353/members.ndjson12
-rw-r--r--spec/helpers/integrations_helper_spec.rb15
-rw-r--r--spec/lib/banzai/filter/references/design_reference_filter_spec.rb46
-rw-r--r--spec/lib/gitlab/import_export/base/relation_factory_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/group/legacy_tree_saver_spec.rb3
-rw-r--r--spec/lib/gitlab/import_export/members_mapper_spec.rb37
-rw-r--r--spec/lib/gitlab/import_export/project/relation_factory_spec.rb4
-rw-r--r--spec/lib/gitlab/import_export/project/tree_saver_spec.rb3
-rw-r--r--spec/migrations/20210811122206_update_external_project_bots_spec.rb25
-rw-r--r--spec/models/design_management/design_spec.rb14
-rw-r--r--spec/models/integrations/datadog_spec.rb12
-rw-r--r--spec/requests/api/graphql/mutations/design_management/upload_spec.rb23
-rw-r--r--spec/requests/users_controller_spec.rb6
-rw-r--r--spec/services/groups/destroy_service_spec.rb133
-rw-r--r--spec/services/jira_connect_subscriptions/create_service_spec.rb28
-rw-r--r--spec/services/resource_access_tokens/create_service_spec.rb12
-rw-r--r--spec/support/shared_examples/lib/gitlab/import_export/relation_factory_shared_examples.rb2
-rw-r--r--spec/workers/concerns/gitlab/github_import/object_importer_spec.rb2
59 files changed, 560 insertions, 214 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index bd53d7575d0..21e1eef9292 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,19 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
+## 14.1.4 (2021-08-31)
+
+### Security (8 changes)
+
+- [Update apollo_upload_server dependency](gitlab-org/security/gitlab@34e7e3b7590fd76d0f618091551651e8065edfd2) ([merge request](gitlab-org/security/gitlab!1700))
+- [Ensure shared group members lose project access after group deletion](gitlab-org/security/gitlab@4a7b8203776b719c06186c1b189a8cf21572fcd4) ([merge request](gitlab-org/security/gitlab!1684))
+- [Fix stored XSS vulnerability in Datadog settings form](gitlab-org/security/gitlab@0906814af604e7fcab54a96bccadcba11207387d) ([merge request](gitlab-org/security/gitlab!1671))
+- [Inherit user external status while creating project bots](gitlab-org/security/gitlab@d5a26c4145d917b5b49e207e03669d2b7e4ee617) ([merge request](gitlab-org/security/gitlab!1665))
+- [Escape issue reference and title for Jira issues](gitlab-org/security/gitlab@4153444b76421ddf3a7fd21f1fc0500700a4e263) ([merge request](gitlab-org/security/gitlab!1662)) **GitLab Enterprise Edition**
+- [Require sign in for .keys endpoint on non-public instances](gitlab-org/security/gitlab@b090b3f6dee6d21d93595c5e46e6c5c7fc30f1fb) ([merge request](gitlab-org/security/gitlab!1658))
+- [Only create jira connect NS subscriptions for admins](gitlab-org/security/gitlab@3f2040c0e2c90f3fcafdbf0f86bd2591bd458dff) ([merge request](gitlab-org/security/gitlab!1648))
+- [Prevent non-admins from configuring Jira connect app](gitlab-org/security/gitlab@fa864c0a2eaf450033f4c594cea07d9f24144cd6) ([merge request](gitlab-org/security/gitlab!1644))
+
## 14.1.3 (2021-08-17)
### Fixed (2 changes)
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index f7e6aaa8b0a..fa88345648b 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-14.1.3 \ No newline at end of file
+14.1.4 \ No newline at end of file
diff --git a/Gemfile b/Gemfile
index 68e4f2df1ff..1f23c765864 100644
--- a/Gemfile
+++ b/Gemfile
@@ -101,7 +101,7 @@ gem 'graphql', '~> 1.11.8'
# TODO: remove app/views/graphiql/rails/editors/show.html.erb when https://github.com/rmosolgo/graphiql-rails/pull/71 is released:
# https://gitlab.com/gitlab-org/gitlab/issues/31747
gem 'graphiql-rails', '~> 1.4.10'
-gem 'apollo_upload_server', '~> 2.0.2'
+gem 'apollo_upload_server', '~> 2.1.0'
gem 'graphql-docs', '~> 1.6.0', group: [:development, :test]
gem 'graphlient', '~> 0.4.0' # Used by BulkImport feature (group::import)
diff --git a/Gemfile.lock b/Gemfile.lock
index 190435b796f..815096c2270 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -84,9 +84,9 @@ GEM
aes_key_wrap (1.1.0)
akismet (3.0.0)
android_key_attestation (0.3.0)
- apollo_upload_server (2.0.2)
+ apollo_upload_server (2.1.0)
+ actionpack (>= 4.2)
graphql (>= 1.8)
- rails (>= 4.2)
asana (0.10.3)
faraday (~> 1.0)
faraday_middleware (~> 1.0)
@@ -1402,7 +1402,7 @@ DEPENDENCIES
acts-as-taggable-on (~> 7.0)
addressable (~> 2.8)
akismet (~> 3.0)
- apollo_upload_server (~> 2.0.2)
+ apollo_upload_server (~> 2.1.0)
asana (~> 0.10.3)
asciidoctor (~> 2.0.10)
asciidoctor-include-ext (~> 0.3.1)
diff --git a/VERSION b/VERSION
index f7e6aaa8b0a..fa88345648b 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-14.1.3 \ No newline at end of file
+14.1.4 \ No newline at end of file
diff --git a/app/controllers/jira_connect/app_descriptor_controller.rb b/app/controllers/jira_connect/app_descriptor_controller.rb
index 0de42ad2452..ca2d502d2fe 100644
--- a/app/controllers/jira_connect/app_descriptor_controller.rb
+++ b/app/controllers/jira_connect/app_descriptor_controller.rb
@@ -58,10 +58,14 @@ class JiraConnect::AppDescriptorController < JiraConnect::ApplicationController
},
postInstallPage: {
key: 'gitlab-configuration',
- name: {
- value: 'GitLab Configuration'
- },
- url: relative_to_base_path(jira_connect_subscriptions_path)
+ name: { value: 'GitLab Configuration' },
+ url: relative_to_base_path(jira_connect_subscriptions_path),
+ conditions: [
+ {
+ condition: 'user_is_admin',
+ invert: false
+ }
+ ]
}
}
diff --git a/app/controllers/jira_connect/application_controller.rb b/app/controllers/jira_connect/application_controller.rb
index a6529ecb4ce..352e78d6255 100644
--- a/app/controllers/jira_connect/application_controller.rb
+++ b/app/controllers/jira_connect/application_controller.rb
@@ -38,12 +38,30 @@ class JiraConnect::ApplicationController < ApplicationController
end
def installation_from_jwt
- return unless auth_token
-
strong_memoize(:installation_from_jwt) do
+ next unless claims['iss']
+
+ JiraConnectInstallation.find_by_client_key(claims['iss'])
+ end
+ end
+
+ def claims
+ strong_memoize(:claims) do
+ next {} unless auth_token
+
# Decode without verification to get `client_key` in `iss`
payload, _ = Atlassian::Jwt.decode(auth_token, nil, false)
- JiraConnectInstallation.find_by_client_key(payload['iss'])
+ payload
+ end
+ end
+
+ def jira_user
+ strong_memoize(:jira_user) do
+ next unless installation_from_jwt
+ next unless claims['sub']
+
+ # This only works for Jira Cloud installations.
+ installation_from_jwt.client.user_info(claims['sub'])
end
end
diff --git a/app/controllers/jira_connect/subscriptions_controller.rb b/app/controllers/jira_connect/subscriptions_controller.rb
index 3ff12f29f10..ef60d387988 100644
--- a/app/controllers/jira_connect/subscriptions_controller.rb
+++ b/app/controllers/jira_connect/subscriptions_controller.rb
@@ -37,7 +37,9 @@ class JiraConnect::SubscriptionsController < JiraConnect::ApplicationController
def destroy
subscription = current_jira_installation.subscriptions.find(params[:id])
- if subscription.destroy
+ if !jira_user&.site_admin?
+ render json: { error: 'forbidden' }, status: :forbidden
+ elsif subscription.destroy
render json: { success: true }
else
render json: { error: subscription.errors.full_messages.join(', ') }, status: :unprocessable_entity
@@ -47,7 +49,7 @@ class JiraConnect::SubscriptionsController < JiraConnect::ApplicationController
private
def create_service
- JiraConnectSubscriptions::CreateService.new(current_jira_installation, current_user, namespace_path: params['namespace_path'])
+ JiraConnectSubscriptions::CreateService.new(current_jira_installation, current_user, namespace_path: params['namespace_path'], jira_user: jira_user)
end
def allow_rendering_in_iframe
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index 1b927afdcf5..30ccceec1af 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -20,7 +20,7 @@ class UsersController < ApplicationController
skip_before_action :authenticate_user!
prepend_before_action(only: [:show]) { authenticate_sessionless_user!(:rss) }
- before_action :user, except: [:exists, :ssh_keys]
+ before_action :user, except: [:exists]
before_action :authorize_read_user_profile!,
only: [:calendar, :calendar_activities, :groups, :projects, :contributed, :starred, :snippets, :followers, :following]
@@ -44,12 +44,7 @@ class UsersController < ApplicationController
# Get all keys of a user(params[:username]) in a text format
# Helpful for sysadmins to put in respective servers
- #
- # Uses `UserFinder` rather than `find_routable!` because this endpoint should
- # be publicly available regardless of instance visibility settings.
def ssh_keys
- user = UserFinder.new(params[:username]).find_by_username
-
render plain: user.all_ssh_keys.join("\n")
end
diff --git a/app/helpers/integrations_helper.rb b/app/helpers/integrations_helper.rb
index ab305d822e8..db7cfbb65c0 100644
--- a/app/helpers/integrations_helper.rb
+++ b/app/helpers/integrations_helper.rb
@@ -118,7 +118,7 @@ module IntegrationsHelper
def jira_issue_breadcrumb_link(issue_reference)
link_to '', { class: 'gl-display-flex gl-align-items-center gl-white-space-nowrap' } do
icon = image_tag image_path('illustrations/logos/jira.svg'), width: 15, height: 15, class: 'gl-mr-2'
- [icon, issue_reference].join.html_safe
+ [icon, html_escape(issue_reference)].join.html_safe
end
end
diff --git a/app/models/design_management/design.rb b/app/models/design_management/design.rb
index 79f5a63bcb6..feb1bf5438c 100644
--- a/app/models/design_management/design.rb
+++ b/app/models/design_management/design.rb
@@ -169,7 +169,7 @@ module DesignManagement
@link_reference_pattern ||= begin
path_segment = %r{issues/#{Gitlab::Regex.issue}/designs}
ext = Regexp.new(Regexp.union(SAFE_IMAGE_EXT + DANGEROUS_IMAGE_EXT).source, Regexp::IGNORECASE)
- valid_char = %r{[^/\s]} # any char that is not a forward slash or whitespace
+ valid_char = %r{[[:word:]\.\-\+]}
filename_pattern = %r{
(?<url_filename> #{valid_char}+ \. #{ext})
}x
diff --git a/app/models/integrations/datadog.rb b/app/models/integrations/datadog.rb
index 27c2fcf266b..0b97ff2cd69 100644
--- a/app/models/integrations/datadog.rb
+++ b/app/models/integrations/datadog.rb
@@ -7,7 +7,6 @@ module Integrations
DEFAULT_DOMAIN = 'datadoghq.com'
URL_TEMPLATE = 'https://webhooks-http-intake.logs.%{datadog_domain}/api/v2/webhook'
- URL_TEMPLATE_API_KEYS = 'https://app.%{datadog_domain}/account/settings#api'
URL_API_KEYS_DOCS = "https://docs.#{DEFAULT_DOMAIN}/account_management/api-app-keys/"
SUPPORTED_EVENTS = %w[
@@ -80,7 +79,7 @@ module Integrations
title: _('API key'),
non_empty_password_title: s_('ProjectService|Enter new API key'),
non_empty_password_help: s_('ProjectService|Leave blank to use your current API key'),
- help: "<a href=\"#{api_keys_url}\" target=\"_blank\">API key</a> used for authentication with Datadog",
+ help: "<a href=\"#{URL_API_KEYS_DOCS}\" target=\"_blank\">API key</a> used for authentication with Datadog",
required: true
},
{
@@ -112,12 +111,6 @@ module Integrations
url.to_s
end
- def api_keys_url
- return URL_API_KEYS_DOCS unless datadog_site.presence
-
- sprintf(URL_TEMPLATE_API_KEYS, datadog_domain: datadog_domain)
- end
-
def execute(data)
object_kind = data[:object_kind]
object_kind = 'job' if object_kind == 'build'
diff --git a/app/models/jira_connect_installation.rb b/app/models/jira_connect_installation.rb
index 7480800abc3..a7e10a5c050 100644
--- a/app/models/jira_connect_installation.rb
+++ b/app/models/jira_connect_installation.rb
@@ -19,4 +19,8 @@ class JiraConnectInstallation < ApplicationRecord
id: JiraConnectSubscription.for_project(project)
})
}
+
+ def client
+ Atlassian::JiraConnect::Client.new(base_url, shared_secret)
+ end
end
diff --git a/app/services/groups/destroy_service.rb b/app/services/groups/destroy_service.rb
index 08c4e0231e7..5ffa746e109 100644
--- a/app/services/groups/destroy_service.rb
+++ b/app/services/groups/destroy_service.rb
@@ -29,14 +29,7 @@ module Groups
group.chat_team&.remove_mattermost_team(current_user)
- # If any other groups are shared with the group that is being destroyed,
- # we should specifically trigger update of all project authorizations
- # for users that are the direct members of this group.
- # If not, the project authorization records of these users to projects within the shared groups
- # will never be removed, causing inconsistencies with access permissions.
- if any_other_groups_are_shared_with_this_group?
- user_ids_for_project_authorizations_refresh = group.users_ids_of_direct_members
- end
+ user_ids_for_project_authorizations_refresh = obtain_user_ids_for_project_authorizations_refresh
group.destroy
@@ -52,9 +45,33 @@ module Groups
private
- def any_other_groups_are_shared_with_this_group?
+ def any_groups_shared_with_this_group?
group.shared_group_links.any?
end
+
+ def any_projects_shared_with_this_group?
+ group.project_group_links.any?
+ end
+
+ # Destroying a group automatically destroys all project authorizations directly
+ # associated with the group and descendents. However, project authorizations
+ # for projects and groups this group is shared with are not. Without a manual
+ # refresh, the project authorization records of these users to shared projects
+ # and projects within the shared groups will never be removed, causing
+ # inconsistencies with access permissions.
+ #
+ # This method retrieves the user IDs that need to be refreshed. If only
+ # groups are shared with this group, only direct members need to be refreshed.
+ # If projects are also shared with the group, direct members *and* shared
+ # members of other groups need to be refreshed.
+ # `Group#user_ids_for_project_authorizations` returns both direct and shared
+ # members' user IDs.
+ def obtain_user_ids_for_project_authorizations_refresh
+ return unless any_projects_shared_with_this_group? || any_groups_shared_with_this_group?
+ return group.user_ids_for_project_authorizations if any_projects_shared_with_this_group?
+
+ group.users_ids_of_direct_members
+ end
end
end
diff --git a/app/services/jira_connect_subscriptions/create_service.rb b/app/services/jira_connect_subscriptions/create_service.rb
index 38e5fe7e690..2f31a3c8d4e 100644
--- a/app/services/jira_connect_subscriptions/create_service.rb
+++ b/app/services/jira_connect_subscriptions/create_service.rb
@@ -5,8 +5,11 @@ module JiraConnectSubscriptions
include Gitlab::Utils::StrongMemoize
MERGE_REQUEST_SYNC_BATCH_SIZE = 20
MERGE_REQUEST_SYNC_BATCH_DELAY = 1.minute.freeze
+ NOT_SITE_ADMIN = 'The Jira user is not a site administrator.'
def execute
+ return error(NOT_SITE_ADMIN, 403) unless can_administer_jira?
+
unless namespace && can?(current_user, :create_jira_connect_subscription, namespace)
return error('Invalid namespace. Please make sure you have sufficient permissions', 401)
end
@@ -16,6 +19,10 @@ module JiraConnectSubscriptions
private
+ def can_administer_jira?
+ @params[:jira_user]&.site_admin?
+ end
+
def create_subscription
subscription = JiraConnectSubscription.new(installation: jira_connect_installation, namespace: namespace)
diff --git a/app/services/resource_access_tokens/create_service.rb b/app/services/resource_access_tokens/create_service.rb
index 34aa414de8f..e0371e5d80f 100644
--- a/app/services/resource_access_tokens/create_service.rb
+++ b/app/services/resource_access_tokens/create_service.rb
@@ -16,6 +16,8 @@ module ResourceAccessTokens
return error(user.errors.full_messages.to_sentence) unless user.persisted?
+ user.update!(external: true) if current_user.external?
+
access_level = params[:access_level] || Gitlab::Access::MAINTAINER
member = create_membership(resource, user, access_level)
diff --git a/config/initializers/apollo_upload_server.rb b/config/initializers/apollo_upload_server.rb
new file mode 100644
index 00000000000..295cb5d8ce8
--- /dev/null
+++ b/config/initializers/apollo_upload_server.rb
@@ -0,0 +1,5 @@
+# frozen_string_literal: true
+
+require 'apollo_upload_server'
+
+ApolloUploadServer::Middleware.strict_mode = true
diff --git a/db/post_migrate/20210811122206_update_external_project_bots.rb b/db/post_migrate/20210811122206_update_external_project_bots.rb
new file mode 100644
index 00000000000..dc2e3d316b0
--- /dev/null
+++ b/db/post_migrate/20210811122206_update_external_project_bots.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+class UpdateExternalProjectBots < ActiveRecord::Migration[6.1]
+ include Gitlab::Database::MigrationHelpers
+
+ class User < ActiveRecord::Base
+ self.table_name = 'users'
+ end
+
+ disable_ddl_transaction!
+
+ TMP_INDEX_NAME = 'tmp_idx_update_external_project_bots'
+
+ def up
+ add_concurrent_index('users', 'id', name: TMP_INDEX_NAME, where: 'external = true')
+
+ ids = ActiveRecord::Base.connection
+ .execute("SELECT u.id FROM users u JOIN users u2 on u2.id = u.created_by_id WHERE u.user_type = 6 AND u2.external = true")
+ .map { |result| result['id'] }
+
+ ids.each_slice(10) do |group|
+ UpdateExternalProjectBots::User.where(id: group).update_all(external: true)
+ end
+
+ remove_concurrent_index_by_name('users', TMP_INDEX_NAME)
+ end
+
+ def down
+ remove_concurrent_index_by_name('users', TMP_INDEX_NAME) if index_exists_by_name?('users', TMP_INDEX_NAME)
+
+ # This migration is irreversible
+ end
+end
diff --git a/db/schema_migrations/20210811122206 b/db/schema_migrations/20210811122206
new file mode 100644
index 00000000000..3bb2799461a
--- /dev/null
+++ b/db/schema_migrations/20210811122206
@@ -0,0 +1 @@
+f6f5e081672fb42adde980fa12f696f5d8fd11921ee52c1472b3d745bb11a5ff \ No newline at end of file
diff --git a/doc/development/import_export.md b/doc/development/import_export.md
index bc1927fffde..2a29df380de 100644
--- a/doc/development/import_export.md
+++ b/doc/development/import_export.md
@@ -259,7 +259,7 @@ Only include the following attributes for the models specified:
included_attributes:
user:
- :id
- - :email
+ - :public_email
# ...
```
diff --git a/doc/integration/jira/connect-app.md b/doc/integration/jira/connect-app.md
index fcee3f7a637..651f8e7d657 100644
--- a/doc/integration/jira/connect-app.md
+++ b/doc/integration/jira/connect-app.md
@@ -6,6 +6,10 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# GitLab.com for Jira Cloud app **(FREE)**
+NOTE:
+Only Jira users with administrator level access are able to install or configure
+the GitLab app for Jira Cloud.
+
## GitLab.com for Jira Cloud app **(FREE SAAS)**
You can integrate GitLab.com and Jira Cloud using the
@@ -39,7 +43,8 @@ For a walkthrough of the integration with GitLab.com for Jira Cloud app, watch
![Sign in to GitLab.com in GitLab.com for Jira Cloud app](img/jira_dev_panel_setup_com_3_v13_9.png)
1. Select **Add namespace** to open the list of available namespaces.
-1. Identify the namespace you want to link, and select **Link**.
+1. Identify the namespace you want to link, and select **Link**. Only Jira site
+ administrators are permitted to add or remove namespaces for an installation.
![Link namespace in GitLab.com for Jira Cloud app](img/jira_dev_panel_setup_com_4_v13_9.png)
diff --git a/doc/user/project/settings/import_export.md b/doc/user/project/settings/import_export.md
index d5fdb86c9b0..7cbc22bef63 100644
--- a/doc/user/project/settings/import_export.md
+++ b/doc/user/project/settings/import_export.md
@@ -44,7 +44,7 @@ Note the following:
- Group members are exported as project members, as long as the user has
maintainer or administrator access to the group where the exported project lives.
- Project members with the [Owner role](../../permissions.md) are imported as Maintainers.
-- Imported users can be mapped by their primary email on self-managed instances, if an administrative user (not an owner) does the import.
+- Imported users can be mapped by their public email on self-managed instances, if an administrative user (not an owner) does the import.
Otherwise, a supplementary comment is left to mention that the original author and
the MRs, notes, or issues are owned by the importer.
- For project migration imports performed over GitLab.com Groups, preserving author information is
diff --git a/lib/atlassian/jira_connect/client.rb b/lib/atlassian/jira_connect/client.rb
index ea83076c49b..f1ba6437b19 100644
--- a/lib/atlassian/jira_connect/client.rb
+++ b/lib/atlassian/jira_connect/client.rb
@@ -30,8 +30,21 @@ module Atlassian
responses.compact
end
+ def user_info(account_id)
+ r = get('/rest/api/3/user', { accountId: account_id, expand: 'groups' })
+
+ JiraUser.new(r.parsed_response) if r.code == 200
+ end
+
private
+ def get(path, query_params)
+ uri = URI.join(@base_uri, path)
+ uri.query = URI.encode_www_form(query_params)
+
+ self.class.get(uri, headers: headers(uri, 'GET'))
+ end
+
def store_ff_info(project:, feature_flags:, **opts)
items = feature_flags.map { |flag| ::Atlassian::JiraConnect::Serializers::FeatureFlagEntity.represent(flag, opts) }
items.reject! { |item| item.issue_keys.empty? }
@@ -99,10 +112,11 @@ module Atlassian
self.class.post(uri, headers: headers(uri), body: metadata.merge(payload).to_json)
end
- def headers(uri)
+ def headers(uri, http_method = 'POST')
{
- 'Authorization' => "JWT #{jwt_token('POST', uri)}",
- 'Content-Type' => 'application/json'
+ 'Authorization' => "JWT #{jwt_token(http_method, uri)}",
+ 'Content-Type' => 'application/json',
+ 'Accept' => 'application/json'
}
end
diff --git a/lib/atlassian/jira_connect/jira_user.rb b/lib/atlassian/jira_connect/jira_user.rb
new file mode 100644
index 00000000000..57ceb8fdf13
--- /dev/null
+++ b/lib/atlassian/jira_connect/jira_user.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+module Atlassian
+ module JiraConnect
+ class JiraUser
+ def initialize(data)
+ @data = data
+ end
+
+ def site_admin?
+ groups = @data.dig('groups', 'items')
+ return false unless groups
+
+ groups.any? { |g| g['name'] == 'site-admins' }
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/import_export/group/import_export.yml b/lib/gitlab/import_export/group/import_export.yml
index 4786c7a52cc..630f918a78b 100644
--- a/lib/gitlab/import_export/group/import_export.yml
+++ b/lib/gitlab/import_export/group/import_export.yml
@@ -20,7 +20,7 @@ tree:
included_attributes:
user:
- :id
- - :email
+ - :public_email
- :username
author:
- :name
diff --git a/lib/gitlab/import_export/group/legacy_import_export.yml b/lib/gitlab/import_export/group/legacy_import_export.yml
index 0a6234f9f02..082d2346f3d 100644
--- a/lib/gitlab/import_export/group/legacy_import_export.yml
+++ b/lib/gitlab/import_export/group/legacy_import_export.yml
@@ -20,7 +20,7 @@ tree:
included_attributes:
user:
- :id
- - :email
+ - :public_email
- :username
author:
- :name
diff --git a/lib/gitlab/import_export/members_mapper.rb b/lib/gitlab/import_export/members_mapper.rb
index ff972cf9352..ce886cb8738 100644
--- a/lib/gitlab/import_export/members_mapper.rb
+++ b/lib/gitlab/import_export/members_mapper.rb
@@ -19,7 +19,8 @@ module Gitlab
@exported_members.inject(missing_keys_tracking_hash) do |hash, member|
if member['user']
old_user_id = member['user']['id']
- existing_user = User.find_by(find_user_query(member))
+ old_user_email = member.dig('user', 'public_email') || member.dig('user', 'email')
+ existing_user = User.find_by(find_user_query(old_user_email)) if old_user_email
hash[old_user_id] = existing_user.id if existing_user && add_team_member(member, existing_user)
else
add_team_member(member)
@@ -94,8 +95,8 @@ module Gitlab
relation_class: relation_class)
end
- def find_user_query(member)
- user_arel[:email].eq(member['user']['email'])
+ def find_user_query(email)
+ user_arel[:email].eq(email)
end
def user_arel
diff --git a/lib/gitlab/import_export/project/import_export.yml b/lib/gitlab/import_export/project/import_export.yml
index a84978a2a80..e5a39efb798 100644
--- a/lib/gitlab/import_export/project/import_export.yml
+++ b/lib/gitlab/import_export/project/import_export.yml
@@ -114,7 +114,7 @@ tree:
included_attributes:
user:
- :id
- - :email
+ - :public_email
- :username
author:
- :name
diff --git a/lib/gitlab/markdown_cache.rb b/lib/gitlab/markdown_cache.rb
index d0702190ac0..0df70ab6e38 100644
--- a/lib/gitlab/markdown_cache.rb
+++ b/lib/gitlab/markdown_cache.rb
@@ -7,7 +7,7 @@ module Gitlab
# cached markdown needs to be updated. As a result, this line should
# not be changed.
# See: https://gitlab.com/gitlab-org/gitlab/-/issues/330313
- CACHE_COMMONMARK_VERSION = 28
+ CACHE_COMMONMARK_VERSION = 29
CACHE_COMMONMARK_VERSION_START = 10
BaseError = Class.new(StandardError)
diff --git a/lib/gitlab/middleware/multipart.rb b/lib/gitlab/middleware/multipart.rb
index 329041e3ba2..b7082bc12ef 100644
--- a/lib/gitlab/middleware/multipart.rb
+++ b/lib/gitlab/middleware/multipart.rb
@@ -176,7 +176,7 @@ module Gitlab
::Gitlab::Middleware::Multipart::Handler.new(env, message).with_open_files do
@app.call(env)
end
- rescue UploadedFile::InvalidPathError => e
+ rescue UploadedFile::InvalidPathError, ApolloUploadServer::GraphQLDataBuilder::OutOfBounds => e
[400, { 'Content-Type' => 'text/plain' }, e.message]
end
end
diff --git a/spec/controllers/jira_connect/subscriptions_controller_spec.rb b/spec/controllers/jira_connect/subscriptions_controller_spec.rb
index 95b359a989a..60729f94288 100644
--- a/spec/controllers/jira_connect/subscriptions_controller_spec.rb
+++ b/spec/controllers/jira_connect/subscriptions_controller_spec.rb
@@ -56,11 +56,17 @@ RSpec.describe JiraConnect::SubscriptionsController do
end
context 'with valid JWT' do
- let(:jwt) { Atlassian::Jwt.encode({ iss: installation.client_key }, installation.shared_secret) }
+ let(:claims) { { iss: installation.client_key, sub: 1234 } }
+ let(:jwt) { Atlassian::Jwt.encode(claims, installation.shared_secret) }
+ let(:jira_user) { { 'groups' => { 'items' => [{ 'name' => jira_group_name }] } } }
+ let(:jira_group_name) { 'site-admins' }
context 'signed in to GitLab' do
before do
sign_in(user)
+ WebMock
+ .stub_request(:get, "#{installation.base_url}/rest/api/3/user?accountId=1234&expand=groups")
+ .to_return(body: jira_user.to_json, status: 200, headers: { 'Content-Type' => 'application/json' })
end
context 'dev panel integration is available' do
@@ -74,6 +80,16 @@ RSpec.describe JiraConnect::SubscriptionsController do
expect(response).to have_gitlab_http_status(:ok)
end
end
+
+ context 'when the Jira user is not a site-admin' do
+ let(:jira_group_name) { 'some-other-group' }
+
+ it 'returns forbidden' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
end
context 'not signed in to GitLab' do
@@ -88,8 +104,14 @@ RSpec.describe JiraConnect::SubscriptionsController do
describe '#destroy' do
let(:subscription) { create(:jira_connect_subscription, installation: installation) }
+ let(:jira_user) { { 'groups' => { 'items' => [{ 'name' => jira_group_name }] } } }
+ let(:jira_group_name) { 'site-admins' }
before do
+ WebMock
+ .stub_request(:get, "#{installation.base_url}/rest/api/3/user?accountId=1234&expand=groups")
+ .to_return(body: jira_user.to_json, status: 200, headers: { 'Content-Type' => 'application/json' })
+
delete :destroy, params: { jwt: jwt, id: subscription.id }
end
@@ -102,12 +124,23 @@ RSpec.describe JiraConnect::SubscriptionsController do
end
context 'with valid JWT' do
- let(:jwt) { Atlassian::Jwt.encode({ iss: installation.client_key }, installation.shared_secret) }
+ let(:claims) { { iss: installation.client_key, sub: 1234 } }
+ let(:jwt) { Atlassian::Jwt.encode(claims, installation.shared_secret) }
it 'deletes the subscription' do
expect { subscription.reload }.to raise_error ActiveRecord::RecordNotFound
expect(response).to have_gitlab_http_status(:ok)
end
+
+ context 'when the Jira user is not a site admin' do
+ let(:jira_group_name) { 'some-other-group' }
+
+ it 'does not delete the subscription' do
+ expect(response).to have_gitlab_http_status(:forbidden)
+
+ expect { subscription.reload }.not_to raise_error
+ end
+ end
end
end
end
diff --git a/spec/features/file_uploads/graphql_add_design_spec.rb b/spec/features/file_uploads/graphql_add_design_spec.rb
index f805ea86b4c..17fbf5f6838 100644
--- a/spec/features/file_uploads/graphql_add_design_spec.rb
+++ b/spec/features/file_uploads/graphql_add_design_spec.rb
@@ -19,8 +19,18 @@ RSpec.describe 'Upload a design through graphQL', :js do
let_it_be(:user) { create(:user, :admin) }
let_it_be(:personal_access_token) { create(:personal_access_token, user: user) }
let_it_be(:design) { create(:design) }
- let_it_be(:operations) { { "operationName": "uploadDesign", "variables": { "files": [], "projectPath": design.project.full_path, "iid": design.issue.iid }, "query": query }.to_json }
let_it_be(:map) { { "1": ["variables.files.0"] }.to_json }
+ let_it_be(:operations) do
+ {
+ "operationName": "uploadDesign",
+ "variables": {
+ "files": [nil],
+ "projectPath": design.project.full_path,
+ "iid": design.issue.iid
+ },
+ "query": query
+ }.to_json
+ end
let(:url) { capybara_url("/api/graphql?private_token=#{personal_access_token.token}") }
let(:file) { fixture_file_upload('spec/fixtures/dk.png') }
diff --git a/spec/fixtures/group.json b/spec/fixtures/group.json
index 86de34e2f3b..a7c699e2b32 100644
--- a/spec/fixtures/group.json
+++ b/spec/fixtures/group.json
@@ -1 +1 @@
-{"name":"H5bp","path":"h5bp","owner_id":null,"created_at":"2020-01-09 12:08:57 UTC","updated_at":"2020-01-09 12:08:57 UTC","description":"A voluptate non sequi temporibus quam at.","avatar":{"url":null},"membership_lock":false,"share_with_group_lock":false,"visibility_level":20,"request_access_enabled":true,"ldap_sync_status":"ready","ldap_sync_error":null,"ldap_sync_last_update_at":null,"ldap_sync_last_successful_update_at":null,"ldap_sync_last_sync_at":null,"lfs_enabled":null,"parent_id":null,"repository_size_limit":null,"require_two_factor_authentication":false,"two_factor_grace_period":48,"plan_id":null,"project_creation_level":2,"file_template_project_id":null,"saml_discovery_token":"JZGRJbe3","custom_project_templates_group_id":null,"auto_devops_enabled":null,"last_ci_minutes_notification_at":null,"last_ci_minutes_usage_notification_level":null,"subgroup_creation_level":1,"emails_disabled":null,"max_pages_size":null,"max_artifacts_size":null,"mentions_disabled":null,"milestones":[],"badges":[],"labels":[{"id":69,"title":"Amfunc","color":"#2658d0","project_id":null,"created_at":"2020-01-09T12:08:57.693Z","updated_at":"2020-01-09T12:08:57.693Z","template":false,"description":null,"group_id":28,"type":"GroupLabel","priorities":[],"textColor":"#FFFFFF"},{"id":68,"title":"Aquacell","color":"#f658e0","project_id":null,"created_at":"2020-01-09T12:08:57.688Z","updated_at":"2020-01-09T12:08:57.688Z","template":false,"description":null,"group_id":28,"type":"GroupLabel","priorities":[],"textColor":"#333333"},{"id":62,"title":"Bryns","color":"#16f0b9","project_id":null,"created_at":"2020-01-09T12:08:57.672Z","updated_at":"2020-01-09T12:08:57.672Z","template":false,"description":null,"group_id":28,"type":"GroupLabel","priorities":[],"textColor":"#FFFFFF"},{"id":61,"title":"Pephfunc","color":"#556319","project_id":null,"created_at":"2020-01-09T12:08:57.669Z","updated_at":"2020-01-09T12:08:57.669Z","template":false,"description":null,"group_id":28,"type":"GroupLabel","priorities":[],"textColor":"#FFFFFF"},{"id":67,"title":"Sinesync","color":"#4c44e8","project_id":null,"created_at":"2020-01-09T12:08:57.685Z","updated_at":"2020-01-09T12:08:57.685Z","template":false,"description":null,"group_id":28,"type":"GroupLabel","priorities":[],"textColor":"#FFFFFF"},{"id":65,"title":"Traphwood","color":"#71b900","project_id":null,"created_at":"2020-01-09T12:08:57.679Z","updated_at":"2020-01-09T12:08:57.679Z","template":false,"description":null,"group_id":28,"type":"GroupLabel","priorities":[],"textColor":"#FFFFFF"},{"id":66,"title":"Tricell","color":"#179ad3","project_id":null,"created_at":"2020-01-09T12:08:57.683Z","updated_at":"2020-01-09T12:08:57.683Z","template":false,"description":null,"group_id":28,"type":"GroupLabel","priorities":[],"textColor":"#FFFFFF"},{"id":63,"title":"Trienceforge","color":"#cb1e0e","project_id":null,"created_at":"2020-01-09T12:08:57.674Z","updated_at":"2020-01-09T12:08:57.674Z","template":false,"description":null,"group_id":28,"type":"GroupLabel","priorities":[],"textColor":"#FFFFFF"},{"id":64,"title":"Trinix","color":"#66ca41","project_id":null,"created_at":"2020-01-09T12:08:57.677Z","updated_at":"2020-01-09T12:08:57.677Z","template":false,"description":null,"group_id":28,"type":"GroupLabel","priorities":[],"textColor":"#FFFFFF"}],"boards":[],"members":[{"id":8,"access_level":10,"source_id":28,"source_type":"Namespace","user_id":13,"notification_level":3,"created_at":"2020-01-09T12:08:57.884Z","updated_at":"2020-01-09T12:08:57.884Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":13,"email":"lorraine@leannon.info","username":"elina.lakin"}},{"id":7,"access_level":30,"source_id":28,"source_type":"Namespace","user_id":1,"notification_level":3,"created_at":"2020-01-09T12:08:57.129Z","updated_at":"2020-01-09T12:08:57.898Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1,"email":"admin@example.com","username":"root"}},{"id":9,"access_level":20,"source_id":28,"source_type":"Namespace","user_id":8,"notification_level":3,"created_at":"2020-01-09T12:08:57.901Z","updated_at":"2020-01-09T12:08:57.901Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":8,"email":"euna_schroeder@bernier.us","username":"loreen_medhurst"}},{"id":10,"access_level":40,"source_id":28,"source_type":"Namespace","user_id":10,"notification_level":3,"created_at":"2020-01-09T12:08:57.918Z","updated_at":"2020-01-09T12:08:57.918Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":10,"email":"glady_green@prohaska.biz","username":"maia_kuhlman"}}],"epics":[{"id":31,"group_id":28,"author_id":13,"assignee_id":null,"iid":1,"updated_by_id":null,"last_edited_by_id":null,"lock_version":0,"start_date":null,"end_date":null,"last_edited_at":null,"created_at":"2020-01-09T12:11:12.006Z","updated_at":"2020-01-09T12:11:12.006Z","title":"Optio nihil consequatur et vel quaerat cupiditate.","description":"Vel molestias repellendus id voluptatem et non. Blanditiis natus veritatis adipisci qui illo. Sed est veritatis facilis dolore voluptas quibusdam aliquam omnis.\n\nFacere delectus quo architecto explicabo dolores. Quis odit nostrum nobis consequuntur cumque est officiis. Maiores ipsa nobis minus incidunt provident.\n\nVoluptate voluptatem debitis facilis architecto commodi vero. Sit quibusdam consectetur ad quis cupiditate. Exercitationem quasi inventore incidunt itaque optio autem accusantium.","start_date_sourcing_milestone_id":null,"due_date_sourcing_milestone_id":null,"start_date_fixed":null,"due_date_fixed":null,"start_date_is_fixed":null,"due_date_is_fixed":null,"closed_by_id":null,"closed_at":null,"parent_id":null,"relative_position":null,"state_id":"opened","start_date_sourcing_epic_id":null,"due_date_sourcing_epic_id":null,"notes":[]},{"id":32,"group_id":28,"author_id":1,"assignee_id":null,"iid":2,"updated_by_id":null,"last_edited_by_id":null,"lock_version":0,"start_date":null,"end_date":null,"last_edited_at":null,"created_at":"2020-01-09T12:11:12.021Z","updated_at":"2020-01-09T12:11:12.021Z","title":"Maxime cumque totam deleniti excepturi iusto qui sint.","description":"Nesciunt ut sit voluptas iusto rem. Sint doloribus ex et aliquam ea. Nihil necessitatibus distinctio similique incidunt. Consequatur voluptatibus excepturi qui quis quia. Quia optio quod non magnam dolorem id molestiae dignissimos.\n\nAt eligendi fuga veritatis accusamus quo dolores. Eos amet dolores nisi illo voluptatem consequuntur alias. Dolor veniam quas est sed. Ex corporis soluta sit ducimus facere et.\n\nEst odit asperiores vel quae quibusdam maiores quod. Debitis libero quo sed sunt voluptas praesentium. Ut nisi qui et culpa. Consequatur atque aut molestiae sint. Quaerat expedita animi distinctio repellat sed.","start_date_sourcing_milestone_id":null,"due_date_sourcing_milestone_id":null,"start_date_fixed":null,"due_date_fixed":null,"start_date_is_fixed":null,"due_date_is_fixed":null,"closed_by_id":null,"closed_at":null,"parent_id":null,"relative_position":null,"state_id":"opened","start_date_sourcing_epic_id":null,"due_date_sourcing_epic_id":null,"notes":[]},{"id":33,"group_id":28,"author_id":8,"assignee_id":null,"iid":3,"updated_by_id":null,"last_edited_by_id":null,"lock_version":0,"start_date":null,"end_date":null,"last_edited_at":null,"created_at":"2020-01-09T12:11:12.035Z","updated_at":"2020-01-09T12:11:12.035Z","title":"Corrupti perferendis labore omnis pariatur dolores aut repellendus quisquam id.","description":"Eligendi est asperiores minus nulla unde ex. Aspernatur repellat vel deleniti molestiae occaecati odio dicta. Ipsam excepturi quia modi ut autem sed. Omnis quae quam quas ut. Et corrupti aut omnis blanditiis.\n\nDolore dolorem accusamus tempore nihil dolores repellendus sed provident. Commodi consectetur blanditiis et consequatur laborum nulla eveniet facilis. Inventore aut officiis fuga est maiores rerum. Sint aspernatur et necessitatibus omnis qui et blanditiis.\n\nFugiat molestias nulla eos labore rerum perspiciatis non. Minus est et ipsum quis animi et. Id praesentium vitae in eum fugiat incidunt. Voluptas ut nemo ut cum saepe quasi dolores unde.","start_date_sourcing_milestone_id":null,"due_date_sourcing_milestone_id":null,"start_date_fixed":null,"due_date_fixed":null,"start_date_is_fixed":null,"due_date_is_fixed":null,"closed_by_id":null,"closed_at":null,"parent_id":null,"relative_position":null,"state_id":"opened","start_date_sourcing_epic_id":null,"due_date_sourcing_epic_id":null,"notes":[]},{"id":34,"group_id":28,"author_id":10,"assignee_id":null,"iid":4,"updated_by_id":null,"last_edited_by_id":null,"lock_version":0,"start_date":null,"end_date":null,"last_edited_at":null,"created_at":"2020-01-09T12:11:12.049Z","updated_at":"2020-01-09T12:11:12.049Z","title":"Architecto ipsa autem ducimus velit harum doloribus odio fugiat.","description":"Eos perferendis commodi labore id. Ipsa esse non voluptatem sit. Odit et et maiores quis adipisci sed earum.\n\nRerum asperiores consequuntur sed odit. Quis architecto nobis dolor sit consectetur. Inventore praesentium est magnam et reprehenderit impedit occaecati similique.\n\nTemporibus culpa ratione vel facilis perspiciatis rerum. Quisquam ut veniam quia sit totam. Quo ipsam quam dolorum quis. Totam porro nesciunt ut temporibus.","start_date_sourcing_milestone_id":null,"due_date_sourcing_milestone_id":null,"start_date_fixed":null,"due_date_fixed":null,"start_date_is_fixed":null,"due_date_is_fixed":null,"closed_by_id":null,"closed_at":null,"parent_id":null,"relative_position":null,"state_id":"opened","start_date_sourcing_epic_id":null,"due_date_sourcing_epic_id":null,"notes":[]},{"id":35,"group_id":28,"author_id":10,"assignee_id":null,"iid":5,"updated_by_id":null,"last_edited_by_id":null,"lock_version":0,"start_date":null,"end_date":null,"last_edited_at":null,"created_at":"2020-01-09T12:11:12.062Z","updated_at":"2020-01-09T12:11:12.062Z","title":"Accusantium illo a sint nobis qui explicabo eum iusto facere aut.","description":"Modi laudantium possimus beatae dolorem molestias ut neque. Voluptatem libero harum id cupiditate. Officia et enim quia dolores at adipisci.\n\nEx officia quia at et vel aut. Esse consequatur officiis magnam vel velit eius. Sit cumque quo qui laborum tempore rerum in.\n\nQuibusdam provident quis molestiae laborum odio commodi. Impedit iure voluptatem possimus necessitatibus et error non. Iure est et ipsa recusandae et.","start_date_sourcing_milestone_id":null,"due_date_sourcing_milestone_id":null,"start_date_fixed":null,"due_date_fixed":null,"start_date_is_fixed":null,"due_date_is_fixed":null,"closed_by_id":null,"closed_at":null,"parent_id":null,"relative_position":null,"state_id":"opened","start_date_sourcing_epic_id":null,"due_date_sourcing_epic_id":null,"notes":[]}]}
+{"name":"H5bp","path":"h5bp","owner_id":null,"created_at":"2020-01-09 12:08:57 UTC","updated_at":"2020-01-09 12:08:57 UTC","description":"A voluptate non sequi temporibus quam at.","avatar":{"url":null},"membership_lock":false,"share_with_group_lock":false,"visibility_level":20,"request_access_enabled":true,"ldap_sync_status":"ready","ldap_sync_error":null,"ldap_sync_last_update_at":null,"ldap_sync_last_successful_update_at":null,"ldap_sync_last_sync_at":null,"lfs_enabled":null,"parent_id":null,"repository_size_limit":null,"require_two_factor_authentication":false,"two_factor_grace_period":48,"plan_id":null,"project_creation_level":2,"file_template_project_id":null,"saml_discovery_token":"JZGRJbe3","custom_project_templates_group_id":null,"auto_devops_enabled":null,"last_ci_minutes_notification_at":null,"last_ci_minutes_usage_notification_level":null,"subgroup_creation_level":1,"emails_disabled":null,"max_pages_size":null,"max_artifacts_size":null,"mentions_disabled":null,"milestones":[],"badges":[],"labels":[{"id":69,"title":"Amfunc","color":"#2658d0","project_id":null,"created_at":"2020-01-09T12:08:57.693Z","updated_at":"2020-01-09T12:08:57.693Z","template":false,"description":null,"group_id":28,"type":"GroupLabel","priorities":[],"textColor":"#FFFFFF"},{"id":68,"title":"Aquacell","color":"#f658e0","project_id":null,"created_at":"2020-01-09T12:08:57.688Z","updated_at":"2020-01-09T12:08:57.688Z","template":false,"description":null,"group_id":28,"type":"GroupLabel","priorities":[],"textColor":"#333333"},{"id":62,"title":"Bryns","color":"#16f0b9","project_id":null,"created_at":"2020-01-09T12:08:57.672Z","updated_at":"2020-01-09T12:08:57.672Z","template":false,"description":null,"group_id":28,"type":"GroupLabel","priorities":[],"textColor":"#FFFFFF"},{"id":61,"title":"Pephfunc","color":"#556319","project_id":null,"created_at":"2020-01-09T12:08:57.669Z","updated_at":"2020-01-09T12:08:57.669Z","template":false,"description":null,"group_id":28,"type":"GroupLabel","priorities":[],"textColor":"#FFFFFF"},{"id":67,"title":"Sinesync","color":"#4c44e8","project_id":null,"created_at":"2020-01-09T12:08:57.685Z","updated_at":"2020-01-09T12:08:57.685Z","template":false,"description":null,"group_id":28,"type":"GroupLabel","priorities":[],"textColor":"#FFFFFF"},{"id":65,"title":"Traphwood","color":"#71b900","project_id":null,"created_at":"2020-01-09T12:08:57.679Z","updated_at":"2020-01-09T12:08:57.679Z","template":false,"description":null,"group_id":28,"type":"GroupLabel","priorities":[],"textColor":"#FFFFFF"},{"id":66,"title":"Tricell","color":"#179ad3","project_id":null,"created_at":"2020-01-09T12:08:57.683Z","updated_at":"2020-01-09T12:08:57.683Z","template":false,"description":null,"group_id":28,"type":"GroupLabel","priorities":[],"textColor":"#FFFFFF"},{"id":63,"title":"Trienceforge","color":"#cb1e0e","project_id":null,"created_at":"2020-01-09T12:08:57.674Z","updated_at":"2020-01-09T12:08:57.674Z","template":false,"description":null,"group_id":28,"type":"GroupLabel","priorities":[],"textColor":"#FFFFFF"},{"id":64,"title":"Trinix","color":"#66ca41","project_id":null,"created_at":"2020-01-09T12:08:57.677Z","updated_at":"2020-01-09T12:08:57.677Z","template":false,"description":null,"group_id":28,"type":"GroupLabel","priorities":[],"textColor":"#FFFFFF"}],"boards":[],"members":[{"id":8,"access_level":10,"source_id":28,"source_type":"Namespace","user_id":13,"notification_level":3,"created_at":"2020-01-09T12:08:57.884Z","updated_at":"2020-01-09T12:08:57.884Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":13,"public_email":"lorraine@leannon.info","username":"elina.lakin"}},{"id":7,"access_level":30,"source_id":28,"source_type":"Namespace","user_id":1,"notification_level":3,"created_at":"2020-01-09T12:08:57.129Z","updated_at":"2020-01-09T12:08:57.898Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1,"public_email":"admin@example.com","username":"root"}},{"id":9,"access_level":20,"source_id":28,"source_type":"Namespace","user_id":8,"notification_level":3,"created_at":"2020-01-09T12:08:57.901Z","updated_at":"2020-01-09T12:08:57.901Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":8,"public_email":"euna_schroeder@bernier.us","username":"loreen_medhurst"}},{"id":10,"access_level":40,"source_id":28,"source_type":"Namespace","user_id":10,"notification_level":3,"created_at":"2020-01-09T12:08:57.918Z","updated_at":"2020-01-09T12:08:57.918Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":10,"public_email":"glady_green@prohaska.biz","username":"maia_kuhlman"}}],"epics":[{"id":31,"group_id":28,"author_id":13,"assignee_id":null,"iid":1,"updated_by_id":null,"last_edited_by_id":null,"lock_version":0,"start_date":null,"end_date":null,"last_edited_at":null,"created_at":"2020-01-09T12:11:12.006Z","updated_at":"2020-01-09T12:11:12.006Z","title":"Optio nihil consequatur et vel quaerat cupiditate.","description":"Vel molestias repellendus id voluptatem et non. Blanditiis natus veritatis adipisci qui illo. Sed est veritatis facilis dolore voluptas quibusdam aliquam omnis.\n\nFacere delectus quo architecto explicabo dolores. Quis odit nostrum nobis consequuntur cumque est officiis. Maiores ipsa nobis minus incidunt provident.\n\nVoluptate voluptatem debitis facilis architecto commodi vero. Sit quibusdam consectetur ad quis cupiditate. Exercitationem quasi inventore incidunt itaque optio autem accusantium.","start_date_sourcing_milestone_id":null,"due_date_sourcing_milestone_id":null,"start_date_fixed":null,"due_date_fixed":null,"start_date_is_fixed":null,"due_date_is_fixed":null,"closed_by_id":null,"closed_at":null,"parent_id":null,"relative_position":null,"state_id":"opened","start_date_sourcing_epic_id":null,"due_date_sourcing_epic_id":null,"notes":[]},{"id":32,"group_id":28,"author_id":1,"assignee_id":null,"iid":2,"updated_by_id":null,"last_edited_by_id":null,"lock_version":0,"start_date":null,"end_date":null,"last_edited_at":null,"created_at":"2020-01-09T12:11:12.021Z","updated_at":"2020-01-09T12:11:12.021Z","title":"Maxime cumque totam deleniti excepturi iusto qui sint.","description":"Nesciunt ut sit voluptas iusto rem. Sint doloribus ex et aliquam ea. Nihil necessitatibus distinctio similique incidunt. Consequatur voluptatibus excepturi qui quis quia. Quia optio quod non magnam dolorem id molestiae dignissimos.\n\nAt eligendi fuga veritatis accusamus quo dolores. Eos amet dolores nisi illo voluptatem consequuntur alias. Dolor veniam quas est sed. Ex corporis soluta sit ducimus facere et.\n\nEst odit asperiores vel quae quibusdam maiores quod. Debitis libero quo sed sunt voluptas praesentium. Ut nisi qui et culpa. Consequatur atque aut molestiae sint. Quaerat expedita animi distinctio repellat sed.","start_date_sourcing_milestone_id":null,"due_date_sourcing_milestone_id":null,"start_date_fixed":null,"due_date_fixed":null,"start_date_is_fixed":null,"due_date_is_fixed":null,"closed_by_id":null,"closed_at":null,"parent_id":null,"relative_position":null,"state_id":"opened","start_date_sourcing_epic_id":null,"due_date_sourcing_epic_id":null,"notes":[]},{"id":33,"group_id":28,"author_id":8,"assignee_id":null,"iid":3,"updated_by_id":null,"last_edited_by_id":null,"lock_version":0,"start_date":null,"end_date":null,"last_edited_at":null,"created_at":"2020-01-09T12:11:12.035Z","updated_at":"2020-01-09T12:11:12.035Z","title":"Corrupti perferendis labore omnis pariatur dolores aut repellendus quisquam id.","description":"Eligendi est asperiores minus nulla unde ex. Aspernatur repellat vel deleniti molestiae occaecati odio dicta. Ipsam excepturi quia modi ut autem sed. Omnis quae quam quas ut. Et corrupti aut omnis blanditiis.\n\nDolore dolorem accusamus tempore nihil dolores repellendus sed provident. Commodi consectetur blanditiis et consequatur laborum nulla eveniet facilis. Inventore aut officiis fuga est maiores rerum. Sint aspernatur et necessitatibus omnis qui et blanditiis.\n\nFugiat molestias nulla eos labore rerum perspiciatis non. Minus est et ipsum quis animi et. Id praesentium vitae in eum fugiat incidunt. Voluptas ut nemo ut cum saepe quasi dolores unde.","start_date_sourcing_milestone_id":null,"due_date_sourcing_milestone_id":null,"start_date_fixed":null,"due_date_fixed":null,"start_date_is_fixed":null,"due_date_is_fixed":null,"closed_by_id":null,"closed_at":null,"parent_id":null,"relative_position":null,"state_id":"opened","start_date_sourcing_epic_id":null,"due_date_sourcing_epic_id":null,"notes":[]},{"id":34,"group_id":28,"author_id":10,"assignee_id":null,"iid":4,"updated_by_id":null,"last_edited_by_id":null,"lock_version":0,"start_date":null,"end_date":null,"last_edited_at":null,"created_at":"2020-01-09T12:11:12.049Z","updated_at":"2020-01-09T12:11:12.049Z","title":"Architecto ipsa autem ducimus velit harum doloribus odio fugiat.","description":"Eos perferendis commodi labore id. Ipsa esse non voluptatem sit. Odit et et maiores quis adipisci sed earum.\n\nRerum asperiores consequuntur sed odit. Quis architecto nobis dolor sit consectetur. Inventore praesentium est magnam et reprehenderit impedit occaecati similique.\n\nTemporibus culpa ratione vel facilis perspiciatis rerum. Quisquam ut veniam quia sit totam. Quo ipsam quam dolorum quis. Totam porro nesciunt ut temporibus.","start_date_sourcing_milestone_id":null,"due_date_sourcing_milestone_id":null,"start_date_fixed":null,"due_date_fixed":null,"start_date_is_fixed":null,"due_date_is_fixed":null,"closed_by_id":null,"closed_at":null,"parent_id":null,"relative_position":null,"state_id":"opened","start_date_sourcing_epic_id":null,"due_date_sourcing_epic_id":null,"notes":[]},{"id":35,"group_id":28,"author_id":10,"assignee_id":null,"iid":5,"updated_by_id":null,"last_edited_by_id":null,"lock_version":0,"start_date":null,"end_date":null,"last_edited_at":null,"created_at":"2020-01-09T12:11:12.062Z","updated_at":"2020-01-09T12:11:12.062Z","title":"Accusantium illo a sint nobis qui explicabo eum iusto facere aut.","description":"Modi laudantium possimus beatae dolorem molestias ut neque. Voluptatem libero harum id cupiditate. Officia et enim quia dolores at adipisci.\n\nEx officia quia at et vel aut. Esse consequatur officiis magnam vel velit eius. Sit cumque quo qui laborum tempore rerum in.\n\nQuibusdam provident quis molestiae laborum odio commodi. Impedit iure voluptatem possimus necessitatibus et error non. Iure est et ipsa recusandae et.","start_date_sourcing_milestone_id":null,"due_date_sourcing_milestone_id":null,"start_date_fixed":null,"due_date_fixed":null,"start_date_is_fixed":null,"due_date_is_fixed":null,"closed_by_id":null,"closed_at":null,"parent_id":null,"relative_position":null,"state_id":"opened","start_date_sourcing_epic_id":null,"due_date_sourcing_epic_id":null,"notes":[]}]}
diff --git a/spec/fixtures/lib/gitlab/import_export/complex/project.json b/spec/fixtures/lib/gitlab/import_export/complex/project.json
index fe885861d00..e3aeace6383 100644
--- a/spec/fixtures/lib/gitlab/import_export/complex/project.json
+++ b/spec/fixtures/lib/gitlab/import_export/complex/project.json
@@ -2398,7 +2398,7 @@
"requested_at": null,
"user": {
"id": 16,
- "email": "bernard_willms@gitlabexample.com",
+ "public_email": "bernard_willms@gitlabexample.com",
"username": "bernard_willms"
}
},
@@ -2418,7 +2418,7 @@
"requested_at": null,
"user": {
"id": 6,
- "email": "saul_will@gitlabexample.com",
+ "public_email": "saul_will@gitlabexample.com",
"username": "saul_will"
}
},
@@ -2438,7 +2438,7 @@
"requested_at": null,
"user": {
"id": 15,
- "email": "breanna_sanford@wolf.com",
+ "public_email": "breanna_sanford@wolf.com",
"username": "emmet.schamberger"
}
},
@@ -2458,7 +2458,7 @@
"requested_at": null,
"user": {
"id": 26,
- "email": "user4@example.com",
+ "public_email": "user4@example.com",
"username": "user4"
}
}
diff --git a/spec/fixtures/lib/gitlab/import_export/complex/tree/project/project_members.ndjson b/spec/fixtures/lib/gitlab/import_export/complex/tree/project/project_members.ndjson
index d8be7b5d164..a010739b32a 100644
--- a/spec/fixtures/lib/gitlab/import_export/complex/tree/project/project_members.ndjson
+++ b/spec/fixtures/lib/gitlab/import_export/complex/tree/project/project_members.ndjson
@@ -1,4 +1,4 @@
-{"id":36,"access_level":40,"source_id":5,"source_type":"Project","user_id":16,"notification_level":3,"created_at":"2016-06-14T15:02:03.834Z","updated_at":"2016-06-14T15:02:03.834Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"user":{"id":16,"email":"bernard_willms@gitlabexample.com","username":"bernard_willms"}}
-{"id":35,"access_level":10,"source_id":5,"source_type":"Project","user_id":6,"notification_level":3,"created_at":"2016-06-14T15:02:03.811Z","updated_at":"2016-06-14T15:02:03.811Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"user":{"id":6,"email":"saul_will@gitlabexample.com","username":"saul_will"}}
-{"id":34,"access_level":20,"source_id":5,"source_type":"Project","user_id":15,"notification_level":3,"created_at":"2016-06-14T15:02:03.776Z","updated_at":"2016-06-14T15:02:03.776Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"user":{"id":15,"email":"breanna_sanford@wolf.com","username":"emmet.schamberger"}}
-{"id":33,"access_level":20,"source_id":5,"source_type":"Project","user_id":26,"notification_level":3,"created_at":"2016-06-14T15:02:03.742Z","updated_at":"2016-06-14T15:02:03.742Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"user":{"id":26,"email":"user4@example.com","username":"user4"}}
+{"id":36,"access_level":40,"source_id":5,"source_type":"Project","user_id":16,"notification_level":3,"created_at":"2016-06-14T15:02:03.834Z","updated_at":"2016-06-14T15:02:03.834Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"user":{"id":16,"public_email":"bernard_willms@gitlabexample.com","username":"bernard_willms"}}
+{"id":35,"access_level":10,"source_id":5,"source_type":"Project","user_id":6,"notification_level":3,"created_at":"2016-06-14T15:02:03.811Z","updated_at":"2016-06-14T15:02:03.811Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"user":{"id":6,"public_email":"saul_will@gitlabexample.com","username":"saul_will"}}
+{"id":34,"access_level":20,"source_id":5,"source_type":"Project","user_id":15,"notification_level":3,"created_at":"2016-06-14T15:02:03.776Z","updated_at":"2016-06-14T15:02:03.776Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"user":{"id":15,"public_email":"breanna_sanford@wolf.com","username":"emmet.schamberger"}}
+{"id":33,"access_level":20,"source_id":5,"source_type":"Project","user_id":26,"notification_level":3,"created_at":"2016-06-14T15:02:03.742Z","updated_at":"2016-06-14T15:02:03.742Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"user":{"id":26,"public_email":"user4@example.com","username":"user4"}}
diff --git a/spec/fixtures/lib/gitlab/import_export/designs/project.json b/spec/fixtures/lib/gitlab/import_export/designs/project.json
index 1d51a726c4c..16dd805c132 100644
--- a/spec/fixtures/lib/gitlab/import_export/designs/project.json
+++ b/spec/fixtures/lib/gitlab/import_export/designs/project.json
@@ -425,7 +425,7 @@
"override":false,
"user":{
"id":1,
- "email":"admin@example.com",
+ "public_email":"admin@example.com",
"username":"root"
}
},
@@ -448,7 +448,7 @@
"override":false,
"user":{
"id":2,
- "email":"user_2@gitlabexample.com",
+ "public_email":"user_2@gitlabexample.com",
"username":"user_2"
}
}
diff --git a/spec/fixtures/lib/gitlab/import_export/group_exports/complex/group.json b/spec/fixtures/lib/gitlab/import_export/group_exports/complex/group.json
index a5a85dc661f..1719e744d04 100644
--- a/spec/fixtures/lib/gitlab/import_export/group_exports/complex/group.json
+++ b/spec/fixtures/lib/gitlab/import_export/group_exports/complex/group.json
@@ -377,7 +377,7 @@
"override": false,
"user": {
"id": 42,
- "email": "moriah@collinsmurphy.com",
+ "public_email": "moriah@collinsmurphy.com",
"username": "reported_user_15"
}
},
@@ -400,7 +400,7 @@
"override": false,
"user": {
"id": 271,
- "email": "garret@connellystark.ca",
+ "public_email": "garret@connellystark.ca",
"username": "charlesetta"
}
},
@@ -423,7 +423,7 @@
"override": false,
"user": {
"id": 206,
- "email": "gwendolyn_robel@gitlabexample.com",
+ "public_email": "gwendolyn_robel@gitlabexample.com",
"username": "gwendolyn_robel"
}
},
@@ -446,7 +446,7 @@
"override": false,
"user": {
"id": 39,
- "email": "alexis_berge@kerlukeklein.us",
+ "public_email": "alexis_berge@kerlukeklein.us",
"username": "reported_user_12"
}
},
@@ -469,7 +469,7 @@
"override": false,
"user": {
"id": 1624,
- "email": "adriene.mcclure@gitlabexample.com",
+ "public_email": "adriene.mcclure@gitlabexample.com",
"username": "adriene.mcclure"
}
},
@@ -492,7 +492,7 @@
"override": false,
"user": {
"id": 1,
- "email": "admin@example.com",
+ "public_email": "admin@example.com",
"username": "root"
}
}
@@ -1338,7 +1338,7 @@
"override": false,
"user": {
"id": 1087,
- "email": "paige@blanda.info",
+ "public_email": "paige@blanda.info",
"username": "billi_auer"
}
},
@@ -1361,7 +1361,7 @@
"override": false,
"user": {
"id": 171,
- "email": "heidi@bosco.co.uk",
+ "public_email": "heidi@bosco.co.uk",
"username": "gerard.cruickshank"
}
},
@@ -1384,7 +1384,7 @@
"override": false,
"user": {
"id": 1157,
- "email": "larisa.bruen@carroll.biz",
+ "public_email": "larisa.bruen@carroll.biz",
"username": "milagros.reynolds"
}
},
@@ -1407,7 +1407,7 @@
"override": false,
"user": {
"id": 14,
- "email": "madlyn_kovacek@wiza.ca",
+ "public_email": "madlyn_kovacek@wiza.ca",
"username": "monique.gusikowski"
}
},
@@ -1430,7 +1430,7 @@
"override": false,
"user": {
"id": 1167,
- "email": "mirella@koepp.ca",
+ "public_email": "mirella@koepp.ca",
"username": "eileen"
}
},
@@ -1453,7 +1453,7 @@
"override": false,
"user": {
"id": 1,
- "email": "admin@example.com",
+ "public_email": "admin@example.com",
"username": "root"
}
}
@@ -1909,7 +1909,7 @@
"override": false,
"user": {
"id": 1533,
- "email": "jose@cassin.ca",
+ "public_email": "jose@cassin.ca",
"username": "buster"
}
},
@@ -1932,7 +1932,7 @@
"override": false,
"user": {
"id": 1586,
- "email": "carie@gleichner.us",
+ "public_email": "carie@gleichner.us",
"username": "dominque"
}
},
@@ -1955,7 +1955,7 @@
"override": false,
"user": {
"id": 190,
- "email": "delois@funk.biz",
+ "public_email": "delois@funk.biz",
"username": "kittie"
}
},
@@ -1978,7 +1978,7 @@
"override": false,
"user": {
"id": 254,
- "email": "tyra.lowe@whitemckenzie.co.uk",
+ "public_email": "tyra.lowe@whitemckenzie.co.uk",
"username": "kassie"
}
},
@@ -2001,7 +2001,7 @@
"override": false,
"user": {
"id": 503,
- "email": "tyesha.brakus@bruen.ca",
+ "public_email": "tyesha.brakus@bruen.ca",
"username": "charise"
}
},
@@ -2024,7 +2024,7 @@
"override": false,
"user": {
"id": 1,
- "email": "admin@example.com",
+ "public_email": "admin@example.com",
"username": "root"
}
}
diff --git a/spec/fixtures/lib/gitlab/import_export/group_exports/complex/tree/groups/4351/members.ndjson b/spec/fixtures/lib/gitlab/import_export/group_exports/complex/tree/groups/4351/members.ndjson
index ec3733a2b2b..74781bfabe2 100644
--- a/spec/fixtures/lib/gitlab/import_export/group_exports/complex/tree/groups/4351/members.ndjson
+++ b/spec/fixtures/lib/gitlab/import_export/group_exports/complex/tree/groups/4351/members.ndjson
@@ -1,6 +1,6 @@
-{"id":13766,"access_level":30,"source_id":4351,"source_type":"Namespace","user_id":42,"notification_level":3,"created_at":"2019-11-20T17:04:36.184Z","updated_at":"2019-11-20T17:04:36.184Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":42,"email":"moriah@collinsmurphy.com","username":"reported_user_15"}}
-{"id":13765,"access_level":40,"source_id":4351,"source_type":"Namespace","user_id":271,"notification_level":3,"created_at":"2019-11-20T17:04:36.044Z","updated_at":"2019-11-20T17:04:36.044Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":271,"email":"garret@connellystark.ca","username":"charlesetta"}}
-{"id":13764,"access_level":30,"source_id":4351,"source_type":"Namespace","user_id":206,"notification_level":3,"created_at":"2019-11-20T17:04:35.840Z","updated_at":"2019-11-20T17:04:35.840Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":206,"email":"gwendolyn_robel@gitlabexample.com","username":"gwendolyn_robel"}}
-{"id":13763,"access_level":10,"source_id":4351,"source_type":"Namespace","user_id":39,"notification_level":3,"created_at":"2019-11-20T17:04:35.704Z","updated_at":"2019-11-20T17:04:35.704Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":39,"email":"alexis_berge@kerlukeklein.us","username":"reported_user_12"}}
-{"id":13762,"access_level":20,"source_id":4351,"source_type":"Namespace","user_id":1624,"notification_level":3,"created_at":"2019-11-20T17:04:35.566Z","updated_at":"2019-11-20T17:04:35.566Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1624,"email":"adriene.mcclure@gitlabexample.com","username":"adriene.mcclure"}}
-{"id":12920,"access_level":50,"source_id":4351,"source_type":"Namespace","user_id":1,"notification_level":3,"created_at":"2019-11-20T17:01:53.505Z","updated_at":"2019-11-20T17:01:53.505Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1,"email":"admin@example.com","username":"root"}}
+{"id":13766,"access_level":30,"source_id":4351,"source_type":"Namespace","user_id":42,"notification_level":3,"created_at":"2019-11-20T17:04:36.184Z","updated_at":"2019-11-20T17:04:36.184Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":42,"public_email":"moriah@collinsmurphy.com","username":"reported_user_15"}}
+{"id":13765,"access_level":40,"source_id":4351,"source_type":"Namespace","user_id":271,"notification_level":3,"created_at":"2019-11-20T17:04:36.044Z","updated_at":"2019-11-20T17:04:36.044Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":271,"public_email":"garret@connellystark.ca","username":"charlesetta"}}
+{"id":13764,"access_level":30,"source_id":4351,"source_type":"Namespace","user_id":206,"notification_level":3,"created_at":"2019-11-20T17:04:35.840Z","updated_at":"2019-11-20T17:04:35.840Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":206,"public_email":"gwendolyn_robel@gitlabexample.com","username":"gwendolyn_robel"}}
+{"id":13763,"access_level":10,"source_id":4351,"source_type":"Namespace","user_id":39,"notification_level":3,"created_at":"2019-11-20T17:04:35.704Z","updated_at":"2019-11-20T17:04:35.704Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":39,"public_email":"alexis_berge@kerlukeklein.us","username":"reported_user_12"}}
+{"id":13762,"access_level":20,"source_id":4351,"source_type":"Namespace","user_id":1624,"notification_level":3,"created_at":"2019-11-20T17:04:35.566Z","updated_at":"2019-11-20T17:04:35.566Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1624,"public_email":"adriene.mcclure@gitlabexample.com","username":"adriene.mcclure"}}
+{"id":12920,"access_level":50,"source_id":4351,"source_type":"Namespace","user_id":1,"notification_level":3,"created_at":"2019-11-20T17:01:53.505Z","updated_at":"2019-11-20T17:01:53.505Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1,"public_email":"admin@example.com","username":"root"}}
diff --git a/spec/fixtures/lib/gitlab/import_export/group_exports/complex/tree/groups/4352/members.ndjson b/spec/fixtures/lib/gitlab/import_export/group_exports/complex/tree/groups/4352/members.ndjson
index 8f9dd22804a..ca586cdcee6 100644
--- a/spec/fixtures/lib/gitlab/import_export/group_exports/complex/tree/groups/4352/members.ndjson
+++ b/spec/fixtures/lib/gitlab/import_export/group_exports/complex/tree/groups/4352/members.ndjson
@@ -1,6 +1,6 @@
-{"id":13771,"access_level":30,"source_id":4352,"source_type":"Namespace","user_id":1087,"notification_level":3,"created_at":"2019-11-20T17:04:36.968Z","updated_at":"2019-11-20T17:04:36.968Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1087,"email":"paige@blanda.info","username":"billi_auer"}}
-{"id":13770,"access_level":20,"source_id":4352,"source_type":"Namespace","user_id":171,"notification_level":3,"created_at":"2019-11-20T17:04:36.821Z","updated_at":"2019-11-20T17:04:36.821Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":171,"email":"heidi@bosco.co.uk","username":"gerard.cruickshank"}}
-{"id":13769,"access_level":30,"source_id":4352,"source_type":"Namespace","user_id":1157,"notification_level":3,"created_at":"2019-11-20T17:04:36.606Z","updated_at":"2019-11-20T17:04:36.606Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1157,"email":"larisa.bruen@carroll.biz","username":"milagros.reynolds"}}
-{"id":13768,"access_level":40,"source_id":4352,"source_type":"Namespace","user_id":14,"notification_level":3,"created_at":"2019-11-20T17:04:36.465Z","updated_at":"2019-11-20T17:04:36.465Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":14,"email":"madlyn_kovacek@wiza.ca","username":"monique.gusikowski"}}
-{"id":13767,"access_level":10,"source_id":4352,"source_type":"Namespace","user_id":1167,"notification_level":3,"created_at":"2019-11-20T17:04:36.324Z","updated_at":"2019-11-20T17:04:36.324Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1167,"email":"mirella@koepp.ca","username":"eileen"}}
-{"id":12921,"access_level":50,"source_id":4352,"source_type":"Namespace","user_id":1,"notification_level":3,"created_at":"2019-11-20T17:01:53.953Z","updated_at":"2019-11-20T17:01:53.953Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1,"email":"admin@example.com","username":"root"}}
+{"id":13771,"access_level":30,"source_id":4352,"source_type":"Namespace","user_id":1087,"notification_level":3,"created_at":"2019-11-20T17:04:36.968Z","updated_at":"2019-11-20T17:04:36.968Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1087,"public_email":"paige@blanda.info","username":"billi_auer"}}
+{"id":13770,"access_level":20,"source_id":4352,"source_type":"Namespace","user_id":171,"notification_level":3,"created_at":"2019-11-20T17:04:36.821Z","updated_at":"2019-11-20T17:04:36.821Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":171,"public_email":"heidi@bosco.co.uk","username":"gerard.cruickshank"}}
+{"id":13769,"access_level":30,"source_id":4352,"source_type":"Namespace","user_id":1157,"notification_level":3,"created_at":"2019-11-20T17:04:36.606Z","updated_at":"2019-11-20T17:04:36.606Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1157,"public_email":"larisa.bruen@carroll.biz","username":"milagros.reynolds"}}
+{"id":13768,"access_level":40,"source_id":4352,"source_type":"Namespace","user_id":14,"notification_level":3,"created_at":"2019-11-20T17:04:36.465Z","updated_at":"2019-11-20T17:04:36.465Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":14,"public_email":"madlyn_kovacek@wiza.ca","username":"monique.gusikowski"}}
+{"id":13767,"access_level":10,"source_id":4352,"source_type":"Namespace","user_id":1167,"notification_level":3,"created_at":"2019-11-20T17:04:36.324Z","updated_at":"2019-11-20T17:04:36.324Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1167,"public_email":"mirella@koepp.ca","username":"eileen"}}
+{"id":12921,"access_level":50,"source_id":4352,"source_type":"Namespace","user_id":1,"notification_level":3,"created_at":"2019-11-20T17:01:53.953Z","updated_at":"2019-11-20T17:01:53.953Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1,"public_email":"admin@example.com","username":"root"}}
diff --git a/spec/fixtures/lib/gitlab/import_export/group_exports/complex/tree/groups/4353/members.ndjson b/spec/fixtures/lib/gitlab/import_export/group_exports/complex/tree/groups/4353/members.ndjson
index 7a36a035c09..78675c4c6c8 100644
--- a/spec/fixtures/lib/gitlab/import_export/group_exports/complex/tree/groups/4353/members.ndjson
+++ b/spec/fixtures/lib/gitlab/import_export/group_exports/complex/tree/groups/4353/members.ndjson
@@ -1,6 +1,6 @@
-{"id":13786,"access_level":30,"source_id":4355,"source_type":"Namespace","user_id":1533,"notification_level":3,"created_at":"2019-11-20T17:04:39.405Z","updated_at":"2019-11-20T17:04:39.405Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1533,"email":"jose@cassin.ca","username":"buster"}}
-{"id":13785,"access_level":10,"source_id":4355,"source_type":"Namespace","user_id":1586,"notification_level":3,"created_at":"2019-11-20T17:04:39.269Z","updated_at":"2019-11-20T17:04:39.269Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1586,"email":"carie@gleichner.us","username":"dominque"}}
-{"id":13784,"access_level":30,"source_id":4355,"source_type":"Namespace","user_id":190,"notification_level":3,"created_at":"2019-11-20T17:04:39.127Z","updated_at":"2019-11-20T17:04:39.127Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":190,"email":"delois@funk.biz","username":"kittie"}}
-{"id":13783,"access_level":20,"source_id":4355,"source_type":"Namespace","user_id":254,"notification_level":3,"created_at":"2019-11-20T17:04:38.971Z","updated_at":"2019-11-20T17:04:38.971Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":254,"email":"tyra.lowe@whitemckenzie.co.uk","username":"kassie"}}
-{"id":13782,"access_level":40,"source_id":4355,"source_type":"Namespace","user_id":503,"notification_level":3,"created_at":"2019-11-20T17:04:38.743Z","updated_at":"2019-11-20T17:04:38.743Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":503,"email":"tyesha.brakus@bruen.ca","username":"charise"}}
-{"id":12924,"access_level":50,"source_id":4355,"source_type":"Namespace","user_id":1,"notification_level":3,"created_at":"2019-11-20T17:01:54.145Z","updated_at":"2019-11-20T17:01:54.145Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1,"email":"admin@example.com","username":"root"}}
+{"id":13786,"access_level":30,"source_id":4355,"source_type":"Namespace","user_id":1533,"notification_level":3,"created_at":"2019-11-20T17:04:39.405Z","updated_at":"2019-11-20T17:04:39.405Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1533,"public_email":"jose@cassin.ca","username":"buster"}}
+{"id":13785,"access_level":10,"source_id":4355,"source_type":"Namespace","user_id":1586,"notification_level":3,"created_at":"2019-11-20T17:04:39.269Z","updated_at":"2019-11-20T17:04:39.269Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1586,"public_email":"carie@gleichner.us","username":"dominque"}}
+{"id":13784,"access_level":30,"source_id":4355,"source_type":"Namespace","user_id":190,"notification_level":3,"created_at":"2019-11-20T17:04:39.127Z","updated_at":"2019-11-20T17:04:39.127Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":190,"public_email":"delois@funk.biz","username":"kittie"}}
+{"id":13783,"access_level":20,"source_id":4355,"source_type":"Namespace","user_id":254,"notification_level":3,"created_at":"2019-11-20T17:04:38.971Z","updated_at":"2019-11-20T17:04:38.971Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":254,"public_email":"tyra.lowe@whitemckenzie.co.uk","username":"kassie"}}
+{"id":13782,"access_level":40,"source_id":4355,"source_type":"Namespace","user_id":503,"notification_level":3,"created_at":"2019-11-20T17:04:38.743Z","updated_at":"2019-11-20T17:04:38.743Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":503,"public_email":"tyesha.brakus@bruen.ca","username":"charise"}}
+{"id":12924,"access_level":50,"source_id":4355,"source_type":"Namespace","user_id":1,"notification_level":3,"created_at":"2019-11-20T17:01:54.145Z","updated_at":"2019-11-20T17:01:54.145Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1,"public_email":"admin@example.com","username":"root"}}
diff --git a/spec/fixtures/lib/gitlab/import_export/group_exports/no_children/group.json b/spec/fixtures/lib/gitlab/import_export/group_exports/no_children/group.json
index 158cd22ed2f..2751f9ab8f2 100644
--- a/spec/fixtures/lib/gitlab/import_export/group_exports/no_children/group.json
+++ b/spec/fixtures/lib/gitlab/import_export/group_exports/no_children/group.json
@@ -299,7 +299,7 @@
"override": false,
"user": {
"id": 42,
- "email": "moriah@collinsmurphy.com",
+ "public_email": "moriah@collinsmurphy.com",
"username": "reported_user_15"
}
},
@@ -322,7 +322,7 @@
"override": false,
"user": {
"id": 271,
- "email": "garret@connellystark.ca",
+ "public_email": "garret@connellystark.ca",
"username": "charlesetta"
}
},
@@ -345,7 +345,7 @@
"override": false,
"user": {
"id": 206,
- "email": "margaret.bergnaum@reynolds.us",
+ "public_email": "margaret.bergnaum@reynolds.us",
"username": "gwendolyn_robel"
}
},
@@ -368,7 +368,7 @@
"override": false,
"user": {
"id": 39,
- "email": "alexis_berge@kerlukeklein.us",
+ "public_email": "alexis_berge@kerlukeklein.us",
"username": "reported_user_12"
}
},
@@ -391,7 +391,7 @@
"override": false,
"user": {
"id": 1624,
- "email": "nakesha.herzog@powlowski.com",
+ "public_email": "nakesha.herzog@powlowski.com",
"username": "adriene.mcclure"
}
},
@@ -414,7 +414,7 @@
"override": false,
"user": {
"id": 1,
- "email": "admin@example.com",
+ "public_email": "admin@example.com",
"username": "root"
}
}
diff --git a/spec/fixtures/lib/gitlab/import_export/group_exports/no_children/tree/groups/4353/members.ndjson b/spec/fixtures/lib/gitlab/import_export/group_exports/no_children/tree/groups/4353/members.ndjson
index 740c724ac5d..09a6d2489d7 100644
--- a/spec/fixtures/lib/gitlab/import_export/group_exports/no_children/tree/groups/4353/members.ndjson
+++ b/spec/fixtures/lib/gitlab/import_export/group_exports/no_children/tree/groups/4353/members.ndjson
@@ -1,6 +1,6 @@
-{"id":13766,"access_level":30,"source_id":4351,"source_type":"Namespace","user_id":42,"notification_level":3,"created_at":"2019-11-20T17:04:36.184Z","updated_at":"2019-11-20T17:04:36.184Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":42,"email":"moriah@collinsmurphy.com","username":"reported_user_15"}}
-{"id":13765,"access_level":40,"source_id":4351,"source_type":"Namespace","user_id":271,"notification_level":3,"created_at":"2019-11-20T17:04:36.044Z","updated_at":"2019-11-20T17:04:36.044Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":271,"email":"garret@connellystark.ca","username":"charlesetta"}}
-{"id":13764,"access_level":30,"source_id":4351,"source_type":"Namespace","user_id":206,"notification_level":3,"created_at":"2019-11-20T17:04:35.840Z","updated_at":"2019-11-20T17:04:35.840Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":206,"email":"margaret.bergnaum@reynolds.us","username":"gwendolyn_robel"}}
-{"id":13763,"access_level":10,"source_id":4351,"source_type":"Namespace","user_id":39,"notification_level":3,"created_at":"2019-11-20T17:04:35.704Z","updated_at":"2019-11-20T17:04:35.704Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":39,"email":"alexis_berge@kerlukeklein.us","username":"reported_user_12"}}
-{"id":13762,"access_level":20,"source_id":4351,"source_type":"Namespace","user_id":1624,"notification_level":3,"created_at":"2019-11-20T17:04:35.566Z","updated_at":"2019-11-20T17:04:35.566Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1624,"email":"nakesha.herzog@powlowski.com","username":"adriene.mcclure"}}
-{"id":12920,"access_level":50,"source_id":4351,"source_type":"Namespace","user_id":1,"notification_level":3,"created_at":"2019-11-20T17:01:53.505Z","updated_at":"2019-11-20T17:01:53.505Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1,"email":"admin@example.com","username":"root"}}
+{"id":13766,"access_level":30,"source_id":4351,"source_type":"Namespace","user_id":42,"notification_level":3,"created_at":"2019-11-20T17:04:36.184Z","updated_at":"2019-11-20T17:04:36.184Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":42,"public_email":"moriah@collinsmurphy.com","username":"reported_user_15"}}
+{"id":13765,"access_level":40,"source_id":4351,"source_type":"Namespace","user_id":271,"notification_level":3,"created_at":"2019-11-20T17:04:36.044Z","updated_at":"2019-11-20T17:04:36.044Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":271,"public_email":"garret@connellystark.ca","username":"charlesetta"}}
+{"id":13764,"access_level":30,"source_id":4351,"source_type":"Namespace","user_id":206,"notification_level":3,"created_at":"2019-11-20T17:04:35.840Z","updated_at":"2019-11-20T17:04:35.840Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":206,"public_email":"margaret.bergnaum@reynolds.us","username":"gwendolyn_robel"}}
+{"id":13763,"access_level":10,"source_id":4351,"source_type":"Namespace","user_id":39,"notification_level":3,"created_at":"2019-11-20T17:04:35.704Z","updated_at":"2019-11-20T17:04:35.704Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":39,"public_email":"alexis_berge@kerlukeklein.us","username":"reported_user_12"}}
+{"id":13762,"access_level":20,"source_id":4351,"source_type":"Namespace","user_id":1624,"notification_level":3,"created_at":"2019-11-20T17:04:35.566Z","updated_at":"2019-11-20T17:04:35.566Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1624,"public_email":"nakesha.herzog@powlowski.com","username":"adriene.mcclure"}}
+{"id":12920,"access_level":50,"source_id":4351,"source_type":"Namespace","user_id":1,"notification_level":3,"created_at":"2019-11-20T17:01:53.505Z","updated_at":"2019-11-20T17:01:53.505Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1,"public_email":"admin@example.com","username":"root"}}
diff --git a/spec/helpers/integrations_helper_spec.rb b/spec/helpers/integrations_helper_spec.rb
index 8e652d2f150..3a7d4d12513 100644
--- a/spec/helpers/integrations_helper_spec.rb
+++ b/spec/helpers/integrations_helper_spec.rb
@@ -98,4 +98,19 @@ RSpec.describe IntegrationsHelper do
end
end
end
+
+ describe '#jira_issue_breadcrumb_link' do
+ let(:issue_reference) { nil }
+
+ subject { helper.jira_issue_breadcrumb_link(issue_reference) }
+
+ context 'when issue_reference contains HTML' do
+ let(:issue_reference) { "<script>alert('XSS')</script>" }
+
+ it 'escapes issue reference' do
+ is_expected.not_to include(issue_reference)
+ is_expected.to include(html_escape(issue_reference))
+ end
+ end
+ end
end
diff --git a/spec/lib/banzai/filter/references/design_reference_filter_spec.rb b/spec/lib/banzai/filter/references/design_reference_filter_spec.rb
index cb1f3d520a4..d616aabea45 100644
--- a/spec/lib/banzai/filter/references/design_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/references/design_reference_filter_spec.rb
@@ -90,11 +90,8 @@ RSpec.describe Banzai::Filter::References::DesignReferenceFilter do
[
['simple.png'],
['SIMPLE.PNG'],
- ['has spaces.png'],
['has-hyphen.jpg'],
- ['snake_case.svg'],
- ['has "quotes".svg'],
- ['has <special> characters [o].svg']
+ ['snake_case.svg']
]
end
@@ -138,40 +135,25 @@ RSpec.describe Banzai::Filter::References::DesignReferenceFilter do
end
end
- context 'a design with a quoted filename' do
- let(:filename) { %q{A "very" good file.png} }
- let(:design) { create(:design, :with_versions, issue: issue, filename: filename) }
-
- it 'links to the design' do
- expect(doc.css('a').first.attr('href'))
- .to eq url_for_design(design)
- end
- end
-
context 'internal reference' do
it_behaves_like 'a reference containing an element node'
- context 'the reference is valid' do
- it_behaves_like 'a good link reference'
+ it_behaves_like 'a good link reference'
- context 'the filename needs to be escaped' do
- where(:filename) do
- [
- ['with some spaces.png'],
- ['with <script>console.log("pwded")<%2Fscript>.png']
- ]
- end
+ context 'the filename contains invalid characters' do
+ where(:filename) do
+ [
+ ['with some spaces.png'],
+ ['with <script>console.log("pwded")<%2Fscript>.png'],
+ ['foo"bar.png'],
+ ['A "very" good file.png']
+ ]
+ end
- with_them do
- let(:design) { create(:design, :with_versions, filename: filename, issue: issue) }
- let(:link) { doc.css('a').first }
+ with_them do
+ let(:design) { create(:design, :with_versions, filename: filename, issue: issue) }
- it 'replaces the content with the reference, but keeps the link', :aggregate_failures do
- expect(doc.text).to eq(CGI.unescapeHTML("Added #{design.to_reference}"))
- expect(link.attr('title')).to eq(design.filename)
- expect(link.attr('href')).to eq(design_url)
- end
- end
+ it_behaves_like 'a no-op filter'
end
end
diff --git a/spec/lib/gitlab/import_export/base/relation_factory_spec.rb b/spec/lib/gitlab/import_export/base/relation_factory_spec.rb
index 6a7ff33465d..bd8873fe20e 100644
--- a/spec/lib/gitlab/import_export/base/relation_factory_spec.rb
+++ b/spec/lib/gitlab/import_export/base/relation_factory_spec.rb
@@ -102,7 +102,7 @@ RSpec.describe Gitlab::ImportExport::Base::RelationFactory do
"updated_at" => "2016-11-18T09:29:42.634Z",
"user" => {
"id" => 999,
- "email" => new_user.email,
+ "public_email" => new_user.email,
"username" => new_user.username
}
}
diff --git a/spec/lib/gitlab/import_export/group/legacy_tree_saver_spec.rb b/spec/lib/gitlab/import_export/group/legacy_tree_saver_spec.rb
index 9e1571ae3d8..e075c5acfea 100644
--- a/spec/lib/gitlab/import_export/group/legacy_tree_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/group/legacy_tree_saver_spec.rb
@@ -83,11 +83,12 @@ RSpec.describe Gitlab::ImportExport::Group::LegacyTreeSaver do
let(:user2) { create(:user, email: 'group@member.com') }
let(:member_emails) do
saved_group_json['members'].map do |pm|
- pm['user']['email']
+ pm['user']['public_email']
end
end
before do
+ user2.update(public_email: user2.email)
group.add_developer(user2)
end
diff --git a/spec/lib/gitlab/import_export/members_mapper_spec.rb b/spec/lib/gitlab/import_export/members_mapper_spec.rb
index 9755e322221..5e8c38eb623 100644
--- a/spec/lib/gitlab/import_export/members_mapper_spec.rb
+++ b/spec/lib/gitlab/import_export/members_mapper_spec.rb
@@ -24,7 +24,7 @@ RSpec.describe Gitlab::ImportExport::MembersMapper do
"user" =>
{
"id" => exported_user_id,
- "email" => user2.email,
+ "public_email" => user2.email,
"username" => 'test'
},
"user_id" => 19
@@ -122,7 +122,7 @@ RSpec.describe Gitlab::ImportExport::MembersMapper do
"user" =>
{
"id" => exported_user_id,
- "email" => user2.email,
+ "public_email" => user2.email,
"username" => 'test'
},
"user_id" => 19
@@ -157,6 +157,37 @@ RSpec.describe Gitlab::ImportExport::MembersMapper do
expect(members_mapper.map[exported_user_id]).to eq(user2.id)
end
end
+
+ context 'when user has email exported' do
+ let(:exported_members) do
+ [
+ {
+ "id" => 2,
+ "access_level" => 40,
+ "source_id" => 14,
+ "source_type" => source_type,
+ "notification_level" => 3,
+ "created_at" => "2016-03-11T10:21:44.822Z",
+ "updated_at" => "2016-03-11T10:21:44.822Z",
+ "created_by_id" => nil,
+ "invite_email" => nil,
+ "invite_token" => nil,
+ "invite_accepted_at" => nil,
+ "user" =>
+ {
+ "id" => exported_user_id,
+ "email" => user2.email,
+ "username" => 'test'
+ },
+ "user_id" => 19
+ }
+ ]
+ end
+
+ it 'maps a member' do
+ expect(members_mapper.map[exported_user_id]).to eq(user2.id)
+ end
+ end
end
context 'when importable is Project' do
@@ -213,7 +244,7 @@ RSpec.describe Gitlab::ImportExport::MembersMapper do
before do
group.add_users([user, user2], GroupMember::DEVELOPER)
- user.update(email: 'invite@test.com')
+ user.update(public_email: 'invite@test.com')
end
it 'maps the importer' do
diff --git a/spec/lib/gitlab/import_export/project/relation_factory_spec.rb b/spec/lib/gitlab/import_export/project/relation_factory_spec.rb
index 38e700e8f9e..88bd71d3d64 100644
--- a/spec/lib/gitlab/import_export/project/relation_factory_spec.rb
+++ b/spec/lib/gitlab/import_export/project/relation_factory_spec.rb
@@ -119,7 +119,7 @@ RSpec.describe Gitlab::ImportExport::Project::RelationFactory, :use_clean_rails_
"updated_at" => "2016-11-18T09:29:42.634Z",
"user" => {
"id" => admin.id,
- "email" => admin.email,
+ "public_email" => admin.email,
"username" => admin.username
}
}
@@ -187,7 +187,7 @@ RSpec.describe Gitlab::ImportExport::Project::RelationFactory, :use_clean_rails_
"updated_at" => "2016-11-18T09:29:42.634Z",
"user" => {
"id" => admin.id,
- "email" => admin.email,
+ "public_email" => admin.email,
"username" => admin.username
}
}
diff --git a/spec/lib/gitlab/import_export/project/tree_saver_spec.rb b/spec/lib/gitlab/import_export/project/tree_saver_spec.rb
index fd6c66a10a7..24e9ac2bb11 100644
--- a/spec/lib/gitlab/import_export/project/tree_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/project/tree_saver_spec.rb
@@ -299,12 +299,13 @@ RSpec.describe Gitlab::ImportExport::Project::TreeSaver do
let(:member_emails) do
emails = subject.map do |pm|
- pm['user']['email']
+ pm['user']['public_email']
end
emails
end
before do
+ user2.update(public_email: user2.email)
group.add_developer(user2)
end
diff --git a/spec/migrations/20210811122206_update_external_project_bots_spec.rb b/spec/migrations/20210811122206_update_external_project_bots_spec.rb
new file mode 100644
index 00000000000..a9c7b485cc6
--- /dev/null
+++ b/spec/migrations/20210811122206_update_external_project_bots_spec.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!('update_external_project_bots')
+
+RSpec.describe UpdateExternalProjectBots, :migration do
+ def create_user(**extra_options)
+ defaults = { projects_limit: 0, email: "#{extra_options[:username]}@example.com" }
+
+ table(:users).create!(defaults.merge(extra_options))
+ end
+
+ it 'sets bot users as external if were created by external users' do
+ internal_user = create_user(username: 'foo')
+ external_user = create_user(username: 'bar', external: true)
+
+ internal_project_bot = create_user(username: 'foo2', user_type: 6, created_by_id: internal_user.id, external: false)
+ external_project_bot = create_user(username: 'bar2', user_type: 6, created_by_id: external_user.id, external: false)
+
+ migrate!
+
+ expect(table(:users).find(internal_project_bot.id).external).to eq false
+ expect(table(:users).find(external_project_bot.id).external).to eq true
+ end
+end
diff --git a/spec/models/design_management/design_spec.rb b/spec/models/design_management/design_spec.rb
index f2ce5e42eaf..b0601ea3f08 100644
--- a/spec/models/design_management/design_spec.rb
+++ b/spec/models/design_management/design_spec.rb
@@ -572,6 +572,12 @@ RSpec.describe DesignManagement::Design do
expect(described_class.link_reference_pattern).not_to match(url_for_designs(issue))
end
+ it 'intentionally ignores filenames with any special character' do
+ design = build(:design, issue: issue, filename: '"invalid')
+
+ expect(described_class.link_reference_pattern).not_to match(url_for_design(design))
+ end
+
where(:ext) do
(described_class::SAFE_IMAGE_EXT + described_class::DANGEROUS_IMAGE_EXT).flat_map do |ext|
[[ext], [ext.upcase]]
@@ -593,14 +599,6 @@ RSpec.describe DesignManagement::Design do
)
end
- context 'the file needs to be encoded' do
- let(:filename) { "my file.#{ext}" }
-
- it 'extracts the encoded filename' do
- expect(captures).to include('url_filename' => 'my%20file.' + ext)
- end
- end
-
context 'the file is all upper case' do
let(:filename) { "file.#{ext}".upcase }
diff --git a/spec/models/integrations/datadog_spec.rb b/spec/models/integrations/datadog_spec.rb
index e2749ab1bc1..2f1ba071130 100644
--- a/spec/models/integrations/datadog_spec.rb
+++ b/spec/models/integrations/datadog_spec.rb
@@ -126,18 +126,6 @@ RSpec.describe Integrations::Datadog do
end
end
- describe '#api_keys_url' do
- subject { instance.api_keys_url }
-
- it { is_expected.to eq("https://app.#{dd_site}/account/settings#api") }
-
- context 'with unset datadog_site' do
- let(:dd_site) { '' }
-
- it { is_expected.to eq("https://docs.datadoghq.com/account_management/api-app-keys/") }
- end
- end
-
describe '#test' do
context 'when request is succesful' do
subject { saved_instance.test(pipeline_data) }
diff --git a/spec/requests/api/graphql/mutations/design_management/upload_spec.rb b/spec/requests/api/graphql/mutations/design_management/upload_spec.rb
index 2189ae3c519..d3e6c689a59 100644
--- a/spec/requests/api/graphql/mutations/design_management/upload_spec.rb
+++ b/spec/requests/api/graphql/mutations/design_management/upload_spec.rb
@@ -11,6 +11,7 @@ RSpec.describe "uploading designs" do
let(:project) { issue.project }
let(:files) { [fixture_file_upload("spec/fixtures/dk.png")] }
let(:variables) { {} }
+ let(:mutation_response) { graphql_mutation_response(:design_management_upload) }
def mutation
input = {
@@ -21,14 +22,32 @@ RSpec.describe "uploading designs" do
graphql_mutation(:design_management_upload, input)
end
- let(:mutation_response) { graphql_mutation_response(:design_management_upload) }
-
before do
enable_design_management
project.add_developer(current_user)
end
+ context 'when the input does not include a null value for each mapped file' do
+ let(:operations) { { query: mutation.query, variables: mutation.variables.merge(files: []) } }
+ let(:mapping) { { '1' => ['variables.files.0'] } }
+ let(:params) do
+ { '1' => files.first, operations: operations.to_json, map: mapping.to_json }
+ end
+
+ it 'returns an error' do
+ workhorse_post_with_file(api('/', current_user, version: 'graphql'),
+ params: params,
+ file_key: '1'
+ )
+
+ expect(response).to have_attributes(
+ code: eq('400'),
+ body: include('out-of-bounds')
+ )
+ end
+ end
+
it "returns an error if the user is not allowed to upload designs" do
post_graphql_mutation_with_uploads(mutation, current_user: create(:user))
diff --git a/spec/requests/users_controller_spec.rb b/spec/requests/users_controller_spec.rb
index 5a38f92221f..accacd705e7 100644
--- a/spec/requests/users_controller_spec.rb
+++ b/spec/requests/users_controller_spec.rb
@@ -274,7 +274,11 @@ RSpec.describe UsersController do
stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
end
- it_behaves_like 'renders all public keys'
+ it 'redirects to sign in' do
+ get "/#{user.username}.keys"
+
+ expect(response).to redirect_to(new_user_session_path)
+ end
end
end
end
diff --git a/spec/services/groups/destroy_service_spec.rb b/spec/services/groups/destroy_service_spec.rb
index c794acdf76d..5135be8fff5 100644
--- a/spec/services/groups/destroy_service_spec.rb
+++ b/spec/services/groups/destroy_service_spec.rb
@@ -152,56 +152,125 @@ RSpec.describe Groups::DestroyService do
end
context 'for shared groups within different hierarchies' do
- let(:shared_with_group) { group }
- let!(:shared_group) { create(:group, :private) }
- let!(:shared_group_child) { create(:group, :private, parent: shared_group) }
- let!(:shared_group_user) { create(:user) }
+ let(:group1) { create(:group, :private) }
+ let(:group2) { create(:group, :private) }
- let!(:project) { create(:project, group: shared_group) }
- let!(:project_child) { create(:project, group: shared_group_child) }
+ let(:group1_user) { create(:user) }
+ let(:group2_user) { create(:user) }
before do
- shared_group.add_user(shared_group_user, Gitlab::Access::OWNER)
-
- create(:group_group_link, shared_group: shared_group, shared_with_group: shared_with_group)
- shared_with_group.refresh_members_authorized_projects
+ group1.add_user(group1_user, Gitlab::Access::OWNER)
+ group2.add_user(group2_user, Gitlab::Access::OWNER)
end
- context 'the shared group is deleted' do
- it 'updates project authorization' do
- expect(shared_group_user.can?(:read_project, project)).to eq(true)
- expect(shared_group_user.can?(:read_project, project_child)).to eq(true)
+ context 'when a project is shared with a group' do
+ let!(:group1_project) { create(:project, :private, group: group1) }
+
+ before do
+ create(:project_group_link, project: group1_project, group: group2)
+ end
+
+ context 'and the shared group is deleted' do
+ it 'updates project authorizations so group2 users no longer have access', :aggregate_failures do
+ expect(group1_user.can?(:read_project, group1_project)).to eq(true)
+ expect(group2_user.can?(:read_project, group1_project)).to eq(true)
- destroy_group(shared_group, shared_group_user, false)
+ destroy_group(group2, group2_user, false)
- expect(shared_group_user.can?(:read_project, project)).to eq(false)
- expect(shared_group_user.can?(:read_project, project_child)).to eq(false)
+ expect(group1_user.can?(:read_project, group1_project)).to eq(true)
+ expect(group2_user.can?(:read_project, group1_project)).to eq(false)
+ end
+
+ it 'calls the service to update project authorizations only with necessary user ids' do
+ expect(UserProjectAccessChangedService)
+ .to receive(:new).with(array_including(group2_user.id)).and_call_original
+
+ destroy_group(group2, group2_user, false)
+ end
end
- it 'does not make use of specific service to update project_authorizations records' do
- expect(UserProjectAccessChangedService)
- .not_to receive(:new).with(shared_group.user_ids_for_project_authorizations).and_call_original
+ context 'and the group is shared with another group' do
+ let(:group3) { create(:group, :private) }
+ let(:group3_user) { create(:user) }
+
+ before do
+ group3.add_user(group3_user, Gitlab::Access::OWNER)
+
+ create(:group_group_link, shared_group: group2, shared_with_group: group3)
+ group3.refresh_members_authorized_projects
+ end
+
+ it 'updates project authorizations so group2 and group3 users no longer have access', :aggregate_failures do
+ expect(group1_user.can?(:read_project, group1_project)).to eq(true)
+ expect(group2_user.can?(:read_project, group1_project)).to eq(true)
+ expect(group3_user.can?(:read_project, group1_project)).to eq(true)
+
+ destroy_group(group2, group2_user, false)
+
+ expect(group1_user.can?(:read_project, group1_project)).to eq(true)
+ expect(group2_user.can?(:read_project, group1_project)).to eq(false)
+ expect(group3_user.can?(:read_project, group1_project)).to eq(false)
+ end
- destroy_group(shared_group, shared_group_user, false)
+ it 'calls the service to update project authorizations only with necessary user ids' do
+ expect(UserProjectAccessChangedService)
+ .to receive(:new).with(array_including(group2_user.id, group3_user.id)).and_call_original
+
+ destroy_group(group2, group2_user, false)
+ end
end
end
- context 'the shared_with group is deleted' do
- it 'updates project authorization' do
- expect(user.can?(:read_project, project)).to eq(true)
- expect(user.can?(:read_project, project_child)).to eq(true)
+ context 'when a group is shared with a group' do
+ let!(:group2_project) { create(:project, :private, group: group2) }
- destroy_group(shared_with_group, user, false)
+ before do
+ create(:group_group_link, shared_group: group2, shared_with_group: group1)
+ group1.refresh_members_authorized_projects
+ end
+
+ context 'and the shared group is deleted' do
+ it 'updates project authorizations since the project has been deleted with the group', :aggregate_failures do
+ expect(group1_user.can?(:read_project, group2_project)).to eq(true)
+ expect(group2_user.can?(:read_project, group2_project)).to eq(true)
+
+ destroy_group(group2, group2_user, false)
- expect(user.can?(:read_project, project)).to eq(false)
- expect(user.can?(:read_project, project_child)).to eq(false)
+ expect(group1_user.can?(:read_project, group2_project)).to eq(false)
+ expect(group2_user.can?(:read_project, group2_project)).to eq(false)
+ end
+
+ it 'does not call the service to update project authorizations' do
+ expect(UserProjectAccessChangedService).not_to receive(:new)
+
+ destroy_group(group2, group2_user, false)
+ end
end
- it 'makes use of a specific service to update project_authorizations records' do
- expect(UserProjectAccessChangedService)
- .to receive(:new).with(shared_with_group.user_ids_for_project_authorizations).and_call_original
+ context 'the shared_with group is deleted' do
+ let!(:group2_subgroup) { create(:group, :private, parent: group2)}
+ let!(:group2_subgroup_project) { create(:project, :private, group: group2_subgroup) }
- destroy_group(shared_with_group, user, false)
+ it 'updates project authorizations so users of both groups lose access', :aggregate_failures do
+ expect(group1_user.can?(:read_project, group2_project)).to eq(true)
+ expect(group2_user.can?(:read_project, group2_project)).to eq(true)
+ expect(group1_user.can?(:read_project, group2_subgroup_project)).to eq(true)
+ expect(group2_user.can?(:read_project, group2_subgroup_project)).to eq(true)
+
+ destroy_group(group1, group1_user, false)
+
+ expect(group1_user.can?(:read_project, group2_project)).to eq(false)
+ expect(group2_user.can?(:read_project, group2_project)).to eq(true)
+ expect(group1_user.can?(:read_project, group2_subgroup_project)).to eq(false)
+ expect(group2_user.can?(:read_project, group2_subgroup_project)).to eq(true)
+ end
+
+ it 'calls the service to update project authorizations only with necessary user ids' do
+ expect(UserProjectAccessChangedService)
+ .to receive(:new).with([group1_user.id]).and_call_original
+
+ destroy_group(group1, group1_user, false)
+ end
end
end
end
diff --git a/spec/services/jira_connect_subscriptions/create_service_spec.rb b/spec/services/jira_connect_subscriptions/create_service_spec.rb
index 5f467a07a78..cde4753cde7 100644
--- a/spec/services/jira_connect_subscriptions/create_service_spec.rb
+++ b/spec/services/jira_connect_subscriptions/create_service_spec.rb
@@ -7,8 +7,10 @@ RSpec.describe JiraConnectSubscriptions::CreateService do
let(:current_user) { create(:user) }
let(:group) { create(:group) }
let(:path) { group.full_path }
+ let(:params) { { namespace_path: path, jira_user: jira_user } }
+ let(:jira_user) { double(:JiraUser, site_admin?: true) }
- subject { described_class.new(installation, current_user, namespace_path: path).execute }
+ subject { described_class.new(installation, current_user, params).execute }
before do
group.add_maintainer(current_user)
@@ -24,6 +26,30 @@ RSpec.describe JiraConnectSubscriptions::CreateService do
end
end
+ context 'remote user does not have access' do
+ let(:jira_user) { double(site_admin?: false) }
+
+ it 'does not create a subscription' do
+ expect { subject }.not_to change { installation.subscriptions.count }
+ end
+
+ it 'returns error' do
+ expect(subject[:status]).to eq(:error)
+ end
+ end
+
+ context 'remote user cannot be retrieved' do
+ let(:jira_user) { nil }
+
+ it 'does not create a subscription' do
+ expect { subject }.not_to change { installation.subscriptions.count }
+ end
+
+ it 'returns error' do
+ expect(subject[:status]).to eq(:error)
+ end
+ end
+
context 'when user does have access' do
it 'creates a subscription' do
expect { subject }.to change { installation.subscriptions.count }.from(0).to(1)
diff --git a/spec/services/resource_access_tokens/create_service_spec.rb b/spec/services/resource_access_tokens/create_service_spec.rb
index 11069dc1bb8..42520ea26b2 100644
--- a/spec/services/resource_access_tokens/create_service_spec.rb
+++ b/spec/services/resource_access_tokens/create_service_spec.rb
@@ -110,6 +110,18 @@ RSpec.describe ResourceAccessTokens::CreateService do
expect(resource.members.developers.map(&:user_id)).to include(bot_user.id)
end
end
+
+ context 'when user is external' do
+ let(:user) { create(:user, :external) }
+
+ before do
+ project.add_maintainer(user)
+ end
+
+ it 'creates resource bot user with external status' do
+ expect(subject.payload[:access_token].user.external).to eq true
+ end
+ end
end
context 'personal access token' do
diff --git a/spec/support/shared_examples/lib/gitlab/import_export/relation_factory_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/import_export/relation_factory_shared_examples.rb
index 3c5c65f0690..9656f3c3520 100644
--- a/spec/support/shared_examples/lib/gitlab/import_export/relation_factory_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/import_export/relation_factory_shared_examples.rb
@@ -19,7 +19,7 @@ RSpec.shared_examples 'Notes user references' do
'updated_at' => '2016-11-18T09:29:42.634Z',
'user' => {
'id' => 999,
- 'email' => mapped_user.email,
+ 'public_email' => mapped_user.email,
'username' => mapped_user.username
}
}
diff --git a/spec/workers/concerns/gitlab/github_import/object_importer_spec.rb b/spec/workers/concerns/gitlab/github_import/object_importer_spec.rb
index 4c96daea7b3..ce02100ebfc 100644
--- a/spec/workers/concerns/gitlab/github_import/object_importer_spec.rb
+++ b/spec/workers/concerns/gitlab/github_import/object_importer_spec.rb
@@ -38,7 +38,7 @@ RSpec.describe Gitlab::GithubImport::ObjectImporter do
end)
end
- describe '#import', :clean_gitlab_redis_shared_state do
+ describe '#import', :clean_gitlab_redis_cache do
let(:importer_class) { double(:importer_class, name: 'klass_name') }
let(:importer_instance) { double(:importer_instance) }
let(:project) { double(:project, full_path: 'foo/bar', id: 1) }