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

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-08-20 03:10:11 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-08-20 03:10:11 +0300
commitb5452c76b5b35884482214dbf6fe9971e0276d3b (patch)
tree45eaee5a27650a3c63a742398054cb666838aae3
parentaf969ba2792f5d872f446398abcf9895573bd292 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--app/assets/javascripts/search_autocomplete.js10
-rw-r--r--app/assets/javascripts/vue_shared/components/date_time_picker/date_time_picker.vue5
-rw-r--r--app/assets/stylesheets/framework/lists.scss6
-rw-r--r--app/assets/stylesheets/pages/members.scss4
-rw-r--r--app/assets/stylesheets/utilities.scss6
-rw-r--r--app/views/layouts/_search.html.haml2
-rw-r--r--app/views/layouts/header/_default.html.haml25
-rw-r--r--app/views/layouts/nav/_dashboard.html.haml2
-rw-r--r--app/views/layouts/nav/sidebar/_group.html.haml2
-rw-r--r--app/views/layouts/nav/sidebar/_profile.html.haml2
-rw-r--r--app/views/layouts/nav/sidebar/_project.html.haml3
-rw-r--r--app/views/projects/issues/_issue.html.haml2
-rw-r--r--app/views/shared/members/_member.html.haml2
-rw-r--r--changelogs/unreleased/223927-write-schema-to-instrument-the-navigation-on-gitlab-com.yml5
-rw-r--r--changelogs/unreleased/24327-add-overarching-auto_link_user-omniauth-configuration.yml5
-rw-r--r--changelogs/unreleased/33767-search-users-in-LDAP-by-their-e-mail-address.yml5
-rw-r--r--changelogs/unreleased/fix-failing-datetimepicker-hide-button.yml5
-rw-r--r--config/gitlab.yml.example5
-rw-r--r--config/initializers/1_settings.rb1
-rw-r--r--config/webpack.config.js2
-rw-r--r--doc/api/groups.md43
-rw-r--r--doc/api/projects.md2
-rw-r--r--doc/integration/jira_development_panel.md3
-rw-r--r--doc/integration/omniauth.md17
-rw-r--r--doc/user/application_security/coverage_fuzzing/index.md14
-rw-r--r--doc/user/group/saml_sso/index.md2
-rw-r--r--doc/user/project/integrations/jira.md3
-rw-r--r--lib/gitlab/auth/o_auth/user.rb6
-rw-r--r--locale/gitlab.pot3
-rw-r--r--spec/frontend/search_autocomplete_spec.js24
-rw-r--r--spec/frontend/vue_shared/components/date_time_picker/date_time_picker_spec.js4
-rw-r--r--spec/lib/gitlab/auth/o_auth/user_spec.rb194
32 files changed, 349 insertions, 65 deletions
diff --git a/app/assets/javascripts/search_autocomplete.js b/app/assets/javascripts/search_autocomplete.js
index 05e0b9e7089..990c8faf253 100644
--- a/app/assets/javascripts/search_autocomplete.js
+++ b/app/assets/javascripts/search_autocomplete.js
@@ -12,6 +12,7 @@ import {
getProjectSlug,
spriteIcon,
} from './lib/utils/common_utils';
+import Tracking from '~/tracking';
/**
* Search input in top navigation bar.
@@ -355,6 +356,15 @@ export class SearchAutocomplete {
if (!this.dropdown.hasClass('show')) {
this.loadingSuggestions = false;
this.dropdownToggle.dropdown('toggle');
+
+ const trackEvent = 'click_search_bar';
+ const trackCategory = undefined; // will be default set in event method
+
+ Tracking.event(trackCategory, trackEvent, {
+ label: 'main_navigation',
+ property: 'navigation',
+ });
+
return this.searchInput.removeClass('js-autocomplete-disabled');
}
}
diff --git a/app/assets/javascripts/vue_shared/components/date_time_picker/date_time_picker.vue b/app/assets/javascripts/vue_shared/components/date_time_picker/date_time_picker.vue
index d932588bee1..3b6b0a91e97 100644
--- a/app/assets/javascripts/vue_shared/components/date_time_picker/date_time_picker.vue
+++ b/app/assets/javascripts/vue_shared/components/date_time_picker/date_time_picker.vue
@@ -213,6 +213,7 @@ export default {
class="d-inline-block"
>
<gl-deprecated-dropdown
+ ref="dropdown"
:text="timeWindowText"
v-bind="$attrs"
class="date-time-picker w-100"
@@ -250,7 +251,9 @@ export default {
/>
</div>
<gl-form-group>
- <gl-button @click="closeDropdown">{{ __('Cancel') }}</gl-button>
+ <gl-button data-testid="cancelButton" @click="closeDropdown">{{
+ __('Cancel')
+ }}</gl-button>
<gl-button
variant="success"
category="primary"
diff --git a/app/assets/stylesheets/framework/lists.scss b/app/assets/stylesheets/framework/lists.scss
index 738150dbd2e..9d67b175294 100644
--- a/app/assets/stylesheets/framework/lists.scss
+++ b/app/assets/stylesheets/framework/lists.scss
@@ -132,10 +132,10 @@ ul.content-list {
a {
color: $gl-text-color;
- }
- .member-group-link {
- color: $blue-600;
+ &.inline-link {
+ color: $blue-600;
+ }
}
.description {
diff --git a/app/assets/stylesheets/pages/members.scss b/app/assets/stylesheets/pages/members.scss
index 54bca80194f..2d9a9f3029f 100644
--- a/app/assets/stylesheets/pages/members.scss
+++ b/app/assets/stylesheets/pages/members.scss
@@ -180,10 +180,6 @@
word-break: break-all;
}
- .member-group-link {
- display: inline-block;
- }
-
.form-control {
width: inherit;
}
diff --git a/app/assets/stylesheets/utilities.scss b/app/assets/stylesheets/utilities.scss
index f99efa743c0..99a13cc4e44 100644
--- a/app/assets/stylesheets/utilities.scss
+++ b/app/assets/stylesheets/utilities.scss
@@ -14,12 +14,6 @@
#{'.text-#{$variant}-#{$suffix}'} {
color: $color;
}
-
- #{'.hover-text-#{$variant}-#{$suffix}'} {
- &:hover {
- color: $color;
- }
- }
}
}
diff --git a/app/views/layouts/_search.html.haml b/app/views/layouts/_search.html.haml
index 4c87920ad89..0c6932e59a9 100644
--- a/app/views/layouts/_search.html.haml
+++ b/app/views/layouts/_search.html.haml
@@ -1,5 +1,5 @@
.search.search-form{ data: { track_label: "navbar_search", track_event: "activate_form_input", track_value: "" } }
- = form_tag search_path, method: :get, class: 'form-inline' do |f|
+ = form_tag search_path, method: :get, class: 'form-inline' do |_f|
.search-input-container
.search-input-wrap
.dropdown{ data: { url: search_autocomplete_path } }
diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml
index ea5a663a654..56b70c463d0 100644
--- a/app/views/layouts/header/_default.html.haml
+++ b/app/views/layouts/header/_default.html.haml
@@ -7,7 +7,7 @@
.title-container
%h1.title
%span.gl-sr-only GitLab
- = link_to root_path, title: _('Dashboard'), id: 'logo' do
+ = link_to root_path, title: _('Dashboard'), id: 'logo', **tracking_attrs('main_navigation', 'click_gitlab_logo_link', 'navigation') do
= brand_header_logo
- logo_text = brand_header_logo_type
- if logo_text.present?
@@ -35,25 +35,40 @@
= sprite_icon('search')
- if header_link?(:issues)
= nav_link(path: 'dashboard#issues', html_options: { class: "user-counter" }) do
- = link_to assigned_issues_dashboard_path, title: _('Issues'), class: 'dashboard-shortcuts-issues', aria: { label: _('Issues') }, data: { qa_selector: 'issues_shortcut_button', toggle: 'tooltip', placement: 'bottom', container: 'body' } do
+ = link_to assigned_issues_dashboard_path, title: _('Issues'), class: 'dashboard-shortcuts-issues', aria: { label: _('Issues') },
+ data: { qa_selector: 'issues_shortcut_button', toggle: 'tooltip', placement: 'bottom',
+ track_label: 'main_navigation',
+ track_event: 'click_issues_link',
+ track_property: 'navigation',
+ container: 'body' } do
= sprite_icon('issues')
- issues_count = assigned_issuables_count(:issues)
%span.badge.badge-pill.issues-count.green-badge{ class: ('hidden' if issues_count == 0) }
= number_with_delimiter(issues_count)
- if header_link?(:merge_requests)
= nav_link(path: 'dashboard#merge_requests', html_options: { class: "user-counter" }) do
- = link_to assigned_mrs_dashboard_path, title: _('Merge requests'), class: 'dashboard-shortcuts-merge_requests', aria: { label: _('Merge requests') }, data: { qa_selector: 'merge_requests_shortcut_button', toggle: 'tooltip', placement: 'bottom', container: 'body' } do
+ = link_to assigned_mrs_dashboard_path, title: _('Merge requests'), class: 'dashboard-shortcuts-merge_requests', aria: { label: _('Merge requests') },
+ data: { qa_selector: 'merge_requests_shortcut_button', toggle: 'tooltip', placement: 'bottom',
+ track_label: 'main_navigation',
+ track_event: 'click_merge_link',
+ track_property: 'navigation',
+ container: 'body' } do
= sprite_icon('git-merge')
- merge_requests_count = assigned_issuables_count(:merge_requests)
%span.badge.badge-pill.merge-requests-count{ class: ('hidden' if merge_requests_count == 0) }
= number_with_delimiter(merge_requests_count)
- if header_link?(:todos)
= nav_link(controller: 'dashboard/todos', html_options: { class: "user-counter" }) do
- = link_to dashboard_todos_path, title: _('To-Do List'), aria: { label: _('To-Do List') }, class: 'shortcuts-todos', data: { qa_selector: 'todos_shortcut_button', toggle: 'tooltip', placement: 'bottom', container: 'body' } do
+ = link_to dashboard_todos_path, title: _('To-Do List'), aria: { label: _('To-Do List') }, class: 'shortcuts-todos',
+ data: { qa_selector: 'todos_shortcut_button', toggle: 'tooltip', placement: 'bottom',
+ track_label: 'main_navigation',
+ track_event: 'click_to_do_link',
+ track_property: 'navigation',
+ container: 'body' } do
= sprite_icon('todo-done')
%span.badge.badge-pill.todos-count{ class: ('hidden' if todos_pending_count == 0) }
= todos_count_format(todos_pending_count)
- %li.nav-item.header-help.dropdown.d-none.d-md-block
+ %li.nav-item.header-help.dropdown.d-none.d-md-block{ **tracking_attrs('main_navigation', 'click_question_mark_link', 'navigation') }
= link_to help_path, class: 'header-help-dropdown-toggle', data: { toggle: "dropdown" } do
%span.gl-sr-only
= s_('Nav|Help')
diff --git a/app/views/layouts/nav/_dashboard.html.haml b/app/views/layouts/nav/_dashboard.html.haml
index e6cfd7d56bb..29cacbe4aff 100644
--- a/app/views/layouts/nav/_dashboard.html.haml
+++ b/app/views/layouts/nav/_dashboard.html.haml
@@ -18,7 +18,7 @@
= render "layouts/nav/groups_dropdown/show"
- if any_dashboard_nav_link?([:groups, :milestones, :activity, :snippets])
- %li.header-more.dropdown
+ %li.header-more.dropdown{ **tracking_attrs('main_navigation', 'click_more_link', 'navigation') }
%a{ href: "#", data: { toggle: "dropdown", qa_selector: 'more_dropdown' } }
= _('More')
= sprite_icon('angle-down', css_class: 'caret-down')
diff --git a/app/views/layouts/nav/sidebar/_group.html.haml b/app/views/layouts/nav/sidebar/_group.html.haml
index 05e6b065dff..47dad21edd7 100644
--- a/app/views/layouts/nav/sidebar/_group.html.haml
+++ b/app/views/layouts/nav/sidebar/_group.html.haml
@@ -1,7 +1,7 @@
- issues_count = group_issues_count(state: 'opened')
- merge_requests_count = group_merge_requests_count(state: 'opened')
-.nav-sidebar{ class: ("sidebar-collapsed-desktop" if collapsed_sidebar?) }
+.nav-sidebar{ class: ("sidebar-collapsed-desktop" if collapsed_sidebar?), **tracking_attrs('groups_side_navigation', 'render', 'groups_side_navigation') }
.nav-sidebar-inner-scroll
.context-header
= link_to group_path(@group), title: @group.name do
diff --git a/app/views/layouts/nav/sidebar/_profile.html.haml b/app/views/layouts/nav/sidebar/_profile.html.haml
index 21b1387f620..dadab554c02 100644
--- a/app/views/layouts/nav/sidebar/_profile.html.haml
+++ b/app/views/layouts/nav/sidebar/_profile.html.haml
@@ -1,4 +1,4 @@
-.nav-sidebar{ class: ("sidebar-collapsed-desktop" if collapsed_sidebar?) }
+.nav-sidebar{ class: ("sidebar-collapsed-desktop" if collapsed_sidebar?), **tracking_attrs('user_side_navigation', 'render', 'user_side_navigation') }
.nav-sidebar-inner-scroll
.context-header
= link_to profile_path, title: _('Profile Settings') do
diff --git a/app/views/layouts/nav/sidebar/_project.html.haml b/app/views/layouts/nav/sidebar/_project.html.haml
index bc9983b710e..054311214ab 100644
--- a/app/views/layouts/nav/sidebar/_project.html.haml
+++ b/app/views/layouts/nav/sidebar/_project.html.haml
@@ -1,6 +1,5 @@
-.nav-sidebar{ class: ("sidebar-collapsed-desktop" if collapsed_sidebar?) }
+.nav-sidebar{ class: ("sidebar-collapsed-desktop" if collapsed_sidebar?), **tracking_attrs('projects_side_navigation', 'render', 'projects_side_navigation') }
.nav-sidebar-inner-scroll
- - can_edit = can?(current_user, :admin_project, @project)
.context-header
= link_to project_path(@project), title: @project.name do
.avatar-container.rect-avatar.s40.project-avatar
diff --git a/app/views/projects/issues/_issue.html.haml b/app/views/projects/issues/_issue.html.haml
index 96d9870514c..ba9ab50cb3a 100644
--- a/app/views/projects/issues/_issue.html.haml
+++ b/app/views/projects/issues/_issue.html.haml
@@ -6,7 +6,7 @@
= check_box_tag dom_id(issue, "selected"), nil, false, 'data-id' => issue.id, class: "selected-issuable"
.issuable-info-container
.issuable-main-info
- .issue-title.title.d-flex.align-items-center
+ .issue-title.title
%span.issue-title-text.js-onboarding-issue-item{ dir: "auto" }
- if issue.confidential?
%span.has-tooltip{ title: _('Confidential') }
diff --git a/app/views/shared/members/_member.html.haml b/app/views/shared/members/_member.html.haml
index 20473b47484..fa71f4dc9b9 100644
--- a/app/views/shared/members/_member.html.haml
+++ b/app/views/shared/members/_member.html.haml
@@ -33,7 +33,7 @@
- if source.instance_of?(Group) && source != @group
&middot;
- = link_to source.full_name, source, class: "member-group-link"
+ = link_to source.full_name, source, class: "gl-display-inline-block inline-link"
.cgray
- if member.request?
diff --git a/changelogs/unreleased/223927-write-schema-to-instrument-the-navigation-on-gitlab-com.yml b/changelogs/unreleased/223927-write-schema-to-instrument-the-navigation-on-gitlab-com.yml
new file mode 100644
index 00000000000..9d37820ff7a
--- /dev/null
+++ b/changelogs/unreleased/223927-write-schema-to-instrument-the-navigation-on-gitlab-com.yml
@@ -0,0 +1,5 @@
+---
+title: Setup basic level telemetry for navigation
+merge_request: 39638
+author:
+type: added
diff --git a/changelogs/unreleased/24327-add-overarching-auto_link_user-omniauth-configuration.yml b/changelogs/unreleased/24327-add-overarching-auto_link_user-omniauth-configuration.yml
new file mode 100644
index 00000000000..87492b1c7ad
--- /dev/null
+++ b/changelogs/unreleased/24327-add-overarching-auto_link_user-omniauth-configuration.yml
@@ -0,0 +1,5 @@
+---
+title: Add auto_link_user OmniAuth setting
+merge_request: 36664
+author:
+type: added
diff --git a/changelogs/unreleased/33767-search-users-in-LDAP-by-their-e-mail-address.yml b/changelogs/unreleased/33767-search-users-in-LDAP-by-their-e-mail-address.yml
new file mode 100644
index 00000000000..7104233838b
--- /dev/null
+++ b/changelogs/unreleased/33767-search-users-in-LDAP-by-their-e-mail-address.yml
@@ -0,0 +1,5 @@
+---
+title: "Allow OAuth to auto link LDAP users via email address"
+merge_request: 33767
+author: Niko Wenselowski
+type: changed
diff --git a/changelogs/unreleased/fix-failing-datetimepicker-hide-button.yml b/changelogs/unreleased/fix-failing-datetimepicker-hide-button.yml
new file mode 100644
index 00000000000..8268005b55b
--- /dev/null
+++ b/changelogs/unreleased/fix-failing-datetimepicker-hide-button.yml
@@ -0,0 +1,5 @@
+---
+title: Fix broken date time picker hide button
+merge_request: 39755
+author:
+type: fixed
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index e16a254e256..5d217332634 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -888,6 +888,11 @@ production: &base
# (default: false)
auto_link_saml_user: false
+ # Allow users with existing accounts to sign in and auto link their account via OmniAuth
+ # login, without having to do a manual login first and manually add OmniAuth. Links on email.
+ # (default: false)
+ auto_link_user: false
+
# Set different Omniauth providers as external so that all users creating accounts
# via these providers will not be able to have access to internal projects. You
# will need to use the full name of the provider, like `google_oauth2` for Google.
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index 9b08f1e5be4..628d9c65ce0 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -83,6 +83,7 @@ Settings.omniauth['external_providers'] = [] if Settings.omniauth['external_prov
Settings.omniauth['block_auto_created_users'] = true if Settings.omniauth['block_auto_created_users'].nil?
Settings.omniauth['auto_link_ldap_user'] = false if Settings.omniauth['auto_link_ldap_user'].nil?
Settings.omniauth['auto_link_saml_user'] = false if Settings.omniauth['auto_link_saml_user'].nil?
+Settings.omniauth['auto_link_user'] = false if Settings.omniauth['auto_link_user'].nil?
Settings.omniauth['sync_profile_from_provider'] = false if Settings.omniauth['sync_profile_from_provider'].nil?
Settings.omniauth['sync_profile_attributes'] = ['email'] if Settings.omniauth['sync_profile_attributes'].nil?
diff --git a/config/webpack.config.js b/config/webpack.config.js
index 49e865d668d..a5b5d0f987d 100644
--- a/config/webpack.config.js
+++ b/config/webpack.config.js
@@ -267,6 +267,8 @@ module.exports = {
runtimeChunk: 'single',
splitChunks: {
maxInitialRequests: 20,
+ // In order to prevent firewalls tripping up: https://gitlab.com/gitlab-org/gitlab/-/issues/22648
+ automaticNameDelimiter: '-',
cacheGroups: {
default: false,
common: () => ({
diff --git a/doc/api/groups.md b/doc/api/groups.md
index 79ac10d4ac6..07b2738f2d3 100644
--- a/doc/api/groups.md
+++ b/doc/api/groups.md
@@ -1164,3 +1164,46 @@ DELETE /groups/:id/share/:group_id
| --------- | -------------- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) |
| `group_id` | integer | yes | The ID of the group to share with |
+
+## Push Rules **(STARTER)**
+
+### Get group push rules
+
+Get the [push rules](../user/group/index.md#group-push-rules-starter) of a group.
+
+```plaintext
+GET /groups/:id/push_rule
+```
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer/string | yes | The ID of the group or [URL-encoded path of the group](README.md#namespaced-path-encoding) |
+
+```json
+{
+ "id": 2,
+ "created_at": "2020-08-17T19:09:19.580Z",
+ "commit_message_regex": "[a-zA-Z]",
+ "commit_message_negative_regex": "[x+]",
+ "branch_name_regex": "[a-z]",
+ "deny_delete_tag": true,
+ "member_check": true,
+ "prevent_secrets": true,
+ "author_email_regex": "^[A-Za-z0-9.]+@gitlab.com$",
+ "file_name_regex": "(exe)$",
+ "max_file_size": 100
+}
+```
+
+Users on GitLab [Premium, Silver, or higher](https://about.gitlab.com/pricing/) will also see
+the `commit_committer_check` and `reject_unsigned_commits` parameters:
+
+```json
+{
+ "id": 2,
+ "created_at": "2020-08-17T19:09:19.580Z",
+ "commit_committer_check": true,
+ "reject_unsigned_commits": false,
+ ...
+}
+```
diff --git a/doc/api/projects.md b/doc/api/projects.md
index 3640008f16d..ee9779b54e0 100644
--- a/doc/api/projects.md
+++ b/doc/api/projects.md
@@ -2124,7 +2124,7 @@ POST /projects/:id/housekeeping
### Get project push rules
-Get the push rules of a project.
+Get the [push rules](../push_rules/push_rules.md#enabling-push-rules) of a project.
```plaintext
GET /projects/:id/push_rule
diff --git a/doc/integration/jira_development_panel.md b/doc/integration/jira_development_panel.md
index 808c7426365..dc19d42ee2e 100644
--- a/doc/integration/jira_development_panel.md
+++ b/doc/integration/jira_development_panel.md
@@ -32,6 +32,9 @@ This differs from the [Jira integration](../user/project/integrations/jira.md),
## Configuration
+<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
+For an overview, see [Agile Management - GitLab-Jira Development Panel Integration](https://www.youtube.com/watch?v=VjVTOmMl85M&feature=youtu.be).
+
- If you're using GitLab.com and Jira Cloud, the recommended method to enable this integration is to install the [GitLab for Jira app](#gitlab-for-jira-app) from the Atlassian Marketplace, which offers a real-time sync between GitLab and Jira.
- If you're using self-managed GitLab, self-managed Jira, or both, configure the integration using [Jira's DVCS Connector](#jira-dvcs-configuration), which syncs data hourly.
diff --git a/doc/integration/omniauth.md b/doc/integration/omniauth.md
index 8ad3f47ce61..9dd7f2cd9e1 100644
--- a/doc/integration/omniauth.md
+++ b/doc/integration/omniauth.md
@@ -140,6 +140,23 @@ OmniAuth provider for an existing user.
The chosen OmniAuth provider is now active and can be used to sign in to GitLab from then on.
+## Automatically Link Existing Users to OmniAuth Users
+
+You can automatically link OmniAuth users with existing GitLab users if their email addresses match by adding the following setting:
+
+**For Omnibus installations**
+
+```ruby
+gitlab_rails['omniauth_auto_link_user'] = true
+```
+
+**For installations from source**
+
+```yaml
+omniauth:
+ auto_link_user: true
+```
+
## Configure OmniAuth Providers as External
> Introduced in GitLab 8.7.
diff --git a/doc/user/application_security/coverage_fuzzing/index.md b/doc/user/application_security/coverage_fuzzing/index.md
index 7fa0e34d90d..1672e9fbb25 100644
--- a/doc/user/application_security/coverage_fuzzing/index.md
+++ b/doc/user/application_security/coverage_fuzzing/index.md
@@ -14,12 +14,14 @@ behavior, such as a crash. Such behavior indicates a bug that you should address
We recommend that you use fuzz testing in addition to the other security scanners in [GitLab Secure](../index.md)
and your own test processes. If you're using [GitLab CI/CD](../../../ci/README.md),
-you can run your coverage guided fuzz tests as part your CI/CD workflow. You can take advantage of
-Coverage Guided Fuzzing by including the CI job in your existing `.gitlab-ci.yml` file.
+you can run your coverage-guided fuzz tests as part your CI/CD workflow. You can take advantage of
+coverage-guided fuzzing by including the CI job in your existing `.gitlab-ci.yml` file.
## Supported fuzzing engines and languages
-GitLab supports these languages through the fuzzing engine listed for each. We currently provide a Docker image for apps written in Go, but you can test the other languages below by providing a Docker image with the fuzz engine to run your app.
+GitLab supports these languages through the fuzzing engine listed for each. We currently provide a
+Docker image for apps written in Go, but you can test the other languages below by providing a
+Docker image with the fuzz engine to run your app.
| Language | Fuzzing Engine | Example |
|----------|----------------|---------|
@@ -65,8 +67,8 @@ The `my_fuzz_target` job (the separate job for your fuzz target) does the follow
The `gitlab-cov-fuzz` is a command-line tool that runs the instrumented application. It parses and
analyzes the exception information that the fuzzer outputs. It also downloads the [corpus](#glossary)
-and crash events from previous pipelines automatically. This helps your fuzz targets build on the progress of
-previous fuzzing jobs. The parsed crash events and data are written to
+and crash events from previous pipelines automatically. This helps your fuzz targets build on the
+progress of previous fuzzing jobs. The parsed crash events and data are written to
`gl-coverage-fuzzing-report.json`.
### Artifacts
@@ -125,7 +127,7 @@ The `gitlab-cov-fuzz` tool emits a JSON report file. For more information, see t
You can download the JSON report file from the CI pipelines page. For more information, see
[Downloading artifacts](../../../ci/pipelines/job_artifacts.md#downloading-artifacts).
-Here's an example Coverage Fuzzing report:
+Here's an example coverage fuzzing report:
```json-doc
{
diff --git a/doc/user/group/saml_sso/index.md b/doc/user/group/saml_sso/index.md
index 17c1011d3b7..f0d0fbff158 100644
--- a/doc/user/group/saml_sso/index.md
+++ b/doc/user/group/saml_sso/index.md
@@ -18,6 +18,8 @@ If you follow our guidance to automate user provisioning using [SCIM](scim_setup
User synchronization of SAML SSO groups is supported through [SCIM](scim_setup.md). SCIM supports adding and removing users from the GitLab group.
For example, if you remove a user from the SCIM app, SCIM removes that same user from the GitLab group.
+SAML SSO is not supported at the subgroup level,
+
## Configuring your Identity Provider
1. Navigate to the group and click **Settings > SAML SSO**.
diff --git a/doc/user/project/integrations/jira.md b/doc/user/project/integrations/jira.md
index 3d23b230322..f11cd4d9539 100644
--- a/doc/user/project/integrations/jira.md
+++ b/doc/user/project/integrations/jira.md
@@ -31,6 +31,9 @@ See the [feature comparison](jira_integrations.md#feature-comparison) for more d
## Configuration
+<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
+For an overview, see [Agile Management - GitLab-Jira Basic Integration](https://www.youtube.com/watch?v=fWvwkx5_00E&feature=youtu.be).
+
Each GitLab project can be configured to connect to an entire Jira instance. That
means one GitLab project can interact with _all_ Jira projects in that instance, once
configured. Therefore, you will not have to explicitly associate
diff --git a/lib/gitlab/auth/o_auth/user.rb b/lib/gitlab/auth/o_auth/user.rb
index bdfef723da8..086f4a2e91c 100644
--- a/lib/gitlab/auth/o_auth/user.rb
+++ b/lib/gitlab/auth/o_auth/user.rb
@@ -62,6 +62,7 @@ module Gitlab
def find_user
user = find_by_uid_and_provider
+ user ||= find_by_email if auto_link_user?
user ||= find_or_build_ldap_user if auto_link_ldap_user?
user ||= build_new_user if signup_enabled?
@@ -150,6 +151,7 @@ module Gitlab
def find_ldap_person(auth_hash, adapter)
Gitlab::Auth::Ldap::Person.find_by_uid(auth_hash.uid, adapter) ||
Gitlab::Auth::Ldap::Person.find_by_email(auth_hash.uid, adapter) ||
+ Gitlab::Auth::Ldap::Person.find_by_email(auth_hash.email, adapter) ||
Gitlab::Auth::Ldap::Person.find_by_dn(auth_hash.uid, adapter)
rescue Gitlab::Auth::Ldap::LdapConnectionError
nil
@@ -269,6 +271,10 @@ module Gitlab
.disabled_oauth_sign_in_sources
.include?(auth_hash.provider)
end
+
+ def auto_link_user?
+ Gitlab.config.omniauth.auto_link_user
+ end
end
end
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index a72573e151d..497757c72d0 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -12593,6 +12593,9 @@ msgstr ""
msgid "How many users will be evaluating the trial?"
msgstr ""
+msgid "How to upgrade"
+msgstr ""
+
msgid "However, you are already a member of this %{member_source}. Sign in using a different account to accept the invitation."
msgstr ""
diff --git a/spec/frontend/search_autocomplete_spec.js b/spec/frontend/search_autocomplete_spec.js
index d0ee43332e8..ee46dc015af 100644
--- a/spec/frontend/search_autocomplete_spec.js
+++ b/spec/frontend/search_autocomplete_spec.js
@@ -3,6 +3,7 @@
import $ from 'jquery';
import '~/gl_dropdown';
import AxiosMockAdapter from 'axios-mock-adapter';
+import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
import initSearchAutocomplete from '~/search_autocomplete';
import '~/lib/utils/common_utils';
import axios from '~/lib/utils/axios_utils';
@@ -274,11 +275,32 @@ describe('Search autocomplete dropdown', () => {
});
describe('enableAutocomplete', () => {
+ let toggleSpy;
+ let trackingSpy;
+
+ beforeEach(() => {
+ toggleSpy = jest.spyOn(widget.dropdownToggle, 'dropdown');
+ trackingSpy = mockTracking('_category_', undefined, jest.spyOn);
+ document.body.dataset.page = 'some:page'; // default tracking for category
+ });
+
+ afterEach(() => {
+ unmockTracking();
+ });
+
it('should open the Dropdown', () => {
- const toggleSpy = jest.spyOn(widget.dropdownToggle, 'dropdown');
widget.enableAutocomplete();
expect(toggleSpy).toHaveBeenCalledWith('toggle');
});
+
+ it('should track the opening', () => {
+ widget.enableAutocomplete();
+
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_search_bar', {
+ label: 'main_navigation',
+ property: 'navigation',
+ });
+ });
});
});
diff --git a/spec/frontend/vue_shared/components/date_time_picker/date_time_picker_spec.js b/spec/frontend/vue_shared/components/date_time_picker/date_time_picker_spec.js
index ceea8d2fa92..223e22d650b 100644
--- a/spec/frontend/vue_shared/components/date_time_picker/date_time_picker_spec.js
+++ b/spec/frontend/vue_shared/components/date_time_picker/date_time_picker_spec.js
@@ -13,9 +13,9 @@ describe('DateTimePicker', () => {
const dropdownToggle = () => wrapper.find('.dropdown-toggle');
const dropdownMenu = () => wrapper.find('.dropdown-menu');
+ const cancelButton = () => wrapper.find('[data-testid="cancelButton"]');
const applyButtonElement = () => wrapper.find('button.btn-success').element;
const findQuickRangeItems = () => wrapper.findAll('.dropdown-item');
- const cancelButtonElement = () => wrapper.find('button.btn-secondary').element;
const createComponent = props => {
wrapper = mount(DateTimePicker, {
@@ -260,7 +260,7 @@ describe('DateTimePicker', () => {
dropdownToggle().trigger('click');
return wrapper.vm.$nextTick(() => {
- cancelButtonElement().click();
+ cancelButton().trigger('click');
return wrapper.vm.$nextTick(() => {
expect(dropdownMenu().classes('show')).toBe(false);
diff --git a/spec/lib/gitlab/auth/o_auth/user_spec.rb b/spec/lib/gitlab/auth/o_auth/user_spec.rb
index cc9e3b957e3..12e774ec1f8 100644
--- a/spec/lib/gitlab/auth/o_auth/user_spec.rb
+++ b/spec/lib/gitlab/auth/o_auth/user_spec.rb
@@ -194,6 +194,43 @@ RSpec.describe Gitlab::Auth::OAuth::User do
end
end
+ context "with auto_link_user disabled (default)" do
+ before do
+ stub_omniauth_config(auto_link_user: false)
+ end
+
+ include_examples "to verify compliance with allow_single_sign_on"
+ end
+
+ context "with auto_link_user enabled" do
+ before do
+ stub_omniauth_config(auto_link_user: true)
+ end
+
+ context "and a current GitLab user with a matching email" do
+ let!(:existing_user) { create(:user, email: 'john@mail.com', username: 'john') }
+
+ it "adds the OmniAuth identity to the GitLab user account" do
+ oauth_user.save
+
+ expect(gl_user).to be_valid
+ expect(gl_user.username).to eql 'john'
+ expect(gl_user.email).to eql 'john@mail.com'
+ expect(gl_user.identities.length).to be 1
+ identities_as_hash = gl_user.identities.map { |id| { provider: id.provider, extern_uid: id.extern_uid } }
+ expect(identities_as_hash).to match_array(
+ [
+ { provider: 'twitter', extern_uid: uid }
+ ]
+ )
+ end
+ end
+
+ context "and no current GitLab user with a matching email" do
+ include_examples "to verify compliance with allow_single_sign_on"
+ end
+ end
+
context "with auto_link_ldap_user disabled (default)" do
before do
stub_omniauth_config(auto_link_ldap_user: false)
@@ -230,39 +267,56 @@ RSpec.describe Gitlab::Auth::OAuth::User do
end
context "and no account for the LDAP user" do
- before do
- allow(Gitlab::Auth::Ldap::Person).to receive(:find_by_uid).and_return(ldap_user)
+ context 'when the LDAP user is found by UID' do
+ before do
+ allow(Gitlab::Auth::Ldap::Person).to receive(:find_by_uid).and_return(ldap_user)
- oauth_user.save
- end
+ oauth_user.save
+ end
- it "creates a user with dual LDAP and omniauth identities" do
- expect(gl_user).to be_valid
- expect(gl_user.username).to eql uid
- expect(gl_user.name).to eql 'John Doe'
- expect(gl_user.email).to eql 'johndoe@example.com'
- expect(gl_user.identities.length).to be 2
- identities_as_hash = gl_user.identities.map { |id| { provider: id.provider, extern_uid: id.extern_uid } }
- expect(identities_as_hash).to match_array(
- [
- { provider: 'ldapmain', extern_uid: dn },
- { provider: 'twitter', extern_uid: uid }
- ]
- )
- end
+ it "creates a user with dual LDAP and omniauth identities" do
+ expect(gl_user).to be_valid
+ expect(gl_user.username).to eql uid
+ expect(gl_user.name).to eql 'John Doe'
+ expect(gl_user.email).to eql 'johndoe@example.com'
+ expect(gl_user.identities.length).to be 2
+ identities_as_hash = gl_user.identities.map { |id| { provider: id.provider, extern_uid: id.extern_uid } }
+ expect(identities_as_hash).to match_array(
+ [
+ { provider: 'ldapmain', extern_uid: dn },
+ { provider: 'twitter', extern_uid: uid }
+ ]
+ )
+ end
- it "has name and email set as synced" do
- expect(gl_user.user_synced_attributes_metadata.name_synced).to be_truthy
- expect(gl_user.user_synced_attributes_metadata.email_synced).to be_truthy
- end
+ it "has name and email set as synced" do
+ expect(gl_user.user_synced_attributes_metadata.name_synced).to be_truthy
+ expect(gl_user.user_synced_attributes_metadata.email_synced).to be_truthy
+ end
- it "has name and email set as read-only" do
- expect(gl_user.read_only_attribute?(:name)).to be_truthy
- expect(gl_user.read_only_attribute?(:email)).to be_truthy
+ it "has name and email set as read-only" do
+ expect(gl_user.read_only_attribute?(:name)).to be_truthy
+ expect(gl_user.read_only_attribute?(:email)).to be_truthy
+ end
+
+ it "has synced attributes provider set to ldapmain" do
+ expect(gl_user.user_synced_attributes_metadata.provider).to eql 'ldapmain'
+ end
end
- it "has synced attributes provider set to ldapmain" do
- expect(gl_user.user_synced_attributes_metadata.provider).to eql 'ldapmain'
+ context 'when the LDAP user is found by email address' do
+ before do
+ allow(Gitlab::Auth::Ldap::Person).to receive(:find_by_uid).and_return(nil)
+ allow(Gitlab::Auth::Ldap::Person).to receive(:find_by_email).with(uid, any_args).and_return(nil)
+ allow(Gitlab::Auth::Ldap::Person).to receive(:find_by_email).with(info_hash[:email], any_args).and_return(ldap_user)
+
+ oauth_user.save
+ end
+
+ it 'creates the LDAP identity' do
+ identities_as_hash = gl_user.identities.map { |id| { provider: id.provider, extern_uid: id.extern_uid } }
+ expect(identities_as_hash).to include({ provider: 'ldapmain', extern_uid: dn })
+ end
end
end
@@ -364,6 +418,90 @@ RSpec.describe Gitlab::Auth::OAuth::User do
end
end
end
+
+ context "with both auto_link_user and auto_link_ldap_user enabled" do
+ before do
+ stub_omniauth_config(auto_link_user: true, auto_link_ldap_user: true)
+ end
+
+ context "and at least one LDAP provider is defined" do
+ before do
+ stub_ldap_config(providers: %w(ldapmain))
+ end
+
+ context "and a corresponding LDAP person" do
+ before do
+ allow(ldap_user).to receive_messages(
+ uid: uid,
+ username: uid,
+ name: 'John Doe',
+ email: ['john@mail.com'],
+ dn: dn
+ )
+ end
+
+ context "and no account for the LDAP user" do
+ before do
+ allow(Gitlab::Auth::Ldap::Person).to receive(:find_by_uid).and_return(ldap_user)
+
+ oauth_user.save
+ end
+
+ it "creates a user with dual LDAP and omniauth identities" do
+ expect(gl_user).to be_valid
+ expect(gl_user.username).to eql uid
+ expect(gl_user.name).to eql 'John Doe'
+ expect(gl_user.email).to eql 'john@mail.com'
+ expect(gl_user.identities.length).to be 2
+ identities_as_hash = gl_user.identities.map { |id| { provider: id.provider, extern_uid: id.extern_uid } }
+ expect(identities_as_hash).to match_array(
+ [
+ { provider: 'ldapmain', extern_uid: dn },
+ { provider: 'twitter', extern_uid: uid }
+ ]
+ )
+ end
+
+ it "has name and email set as synced" do
+ expect(gl_user.user_synced_attributes_metadata.name_synced).to be_truthy
+ expect(gl_user.user_synced_attributes_metadata.email_synced).to be_truthy
+ end
+
+ it "has name and email set as read-only" do
+ expect(gl_user.read_only_attribute?(:name)).to be_truthy
+ expect(gl_user.read_only_attribute?(:email)).to be_truthy
+ end
+
+ it "has synced attributes provider set to ldapmain" do
+ expect(gl_user.user_synced_attributes_metadata.provider).to eql 'ldapmain'
+ end
+ end
+
+ context "and LDAP user has an account already" do
+ let!(:existing_user) { create(:omniauth_user, name: 'John Doe', email: 'john@mail.com', extern_uid: dn, provider: 'ldapmain', username: 'john') }
+
+ it "adds the omniauth identity to the LDAP account" do
+ allow(Gitlab::Auth::Ldap::Person).to receive(:find_by_uid).and_return(ldap_user)
+
+ oauth_user.save
+
+ expect(gl_user).to be_valid
+ expect(gl_user.username).to eql 'john'
+ expect(gl_user.name).to eql 'John Doe'
+ expect(gl_user.email).to eql 'john@mail.com'
+ expect(gl_user.identities.length).to be 2
+ identities_as_hash = gl_user.identities.map { |id| { provider: id.provider, extern_uid: id.extern_uid } }
+ expect(identities_as_hash).to match_array(
+ [
+ { provider: 'ldapmain', extern_uid: dn },
+ { provider: 'twitter', extern_uid: uid }
+ ]
+ )
+ end
+ end
+ end
+ end
+ end
end
describe 'blocking' do
@@ -791,7 +929,7 @@ RSpec.describe Gitlab::Auth::OAuth::User do
end
end
- describe '.find_by_uid_and_provider' do
+ describe '._uid_and_provider' do
let!(:existing_user) { create(:omniauth_user, extern_uid: 'my-uid', provider: 'my-provider') }
it 'normalizes extern_uid' do