diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2019-11-01 00:06:02 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2019-11-01 00:06:02 +0000 |
commit | 8078bd185fd9fce86cb5a8d9a6b6209e0c23ae44 (patch) | |
tree | 6bce184b45888ebeacc7060c84b892ecbd67a4ca | |
parent | 8f210aebe1d740e8ee194f171f1f33a6e1fba313 (diff) | |
download | gitlab-ce-8078bd185fd9fce86cb5a8d9a6b6209e0c23ae44.tar.gz |
Add latest changes from gitlab-org/gitlab@master
36 files changed, 581 insertions, 23 deletions
diff --git a/app/assets/javascripts/monitoring/components/charts/heatmap.vue b/app/assets/javascripts/monitoring/components/charts/heatmap.vue new file mode 100644 index 00000000000..b8158247e49 --- /dev/null +++ b/app/assets/javascripts/monitoring/components/charts/heatmap.vue @@ -0,0 +1,73 @@ +<script> +import { GlHeatmap } from '@gitlab/ui/dist/charts'; +import dateformat from 'dateformat'; +import PrometheusHeader from '../shared/prometheus_header.vue'; +import ResizableChartContainer from '~/vue_shared/components/resizable_chart/resizable_chart_container.vue'; +import { graphDataValidatorForValues } from '../../utils'; + +export default { + components: { + GlHeatmap, + ResizableChartContainer, + PrometheusHeader, + }, + props: { + graphData: { + type: Object, + required: true, + validator: graphDataValidatorForValues.bind(null, false), + }, + containerWidth: { + type: Number, + required: true, + }, + }, + computed: { + chartData() { + return this.queries.result.reduce( + (acc, result, i) => [...acc, ...result.values.map((value, j) => [i, j, value[1]])], + [], + ); + }, + xAxisName() { + return this.graphData.x_label || ''; + }, + yAxisName() { + return this.graphData.y_label || ''; + }, + xAxisLabels() { + return this.queries.result.map(res => Object.values(res.metric)[0]); + }, + yAxisLabels() { + return this.result.values.map(val => { + const [yLabel] = val; + + return dateformat(new Date(yLabel), 'HH:MM:ss'); + }); + }, + result() { + return this.queries.result[0]; + }, + queries() { + return this.graphData.queries[0]; + }, + }, +}; +</script> +<template> + <div class="prometheus-graph col-12 col-lg-6"> + <prometheus-header :graph-title="graphData.title" /> + <resizable-chart-container> + <gl-heatmap + ref="heatmapChart" + v-bind="$attrs" + :data-series="chartData" + :x-axis-name="xAxisName" + :y-axis-name="yAxisName" + :x-axis-labels="xAxisLabels" + :y-axis-labels="yAxisLabels" + :width="containerWidth" + /> + </resizable-chart-container> + </div> +</template> diff --git a/app/assets/javascripts/monitoring/components/panel_type.vue b/app/assets/javascripts/monitoring/components/panel_type.vue index e3f99dbda9a..cafb4b0b479 100644 --- a/app/assets/javascripts/monitoring/components/panel_type.vue +++ b/app/assets/javascripts/monitoring/components/panel_type.vue @@ -13,6 +13,7 @@ import Icon from '~/vue_shared/components/icon.vue'; import MonitorTimeSeriesChart from './charts/time_series.vue'; import MonitorAnomalyChart from './charts/anomaly.vue'; import MonitorSingleStatChart from './charts/single_stat.vue'; +import MonitorHeatmapChart from './charts/heatmap.vue'; import MonitorEmptyChart from './charts/empty_chart.vue'; import TrackEventDirective from '~/vue_shared/directives/track_event'; import { downloadCSVOptions, generateLinkToChartOptions } from '../utils'; @@ -20,6 +21,7 @@ import { downloadCSVOptions, generateLinkToChartOptions } from '../utils'; export default { components: { MonitorSingleStatChart, + MonitorHeatmapChart, MonitorEmptyChart, Icon, GlDropdown, @@ -99,6 +101,11 @@ export default { v-if="isPanelType('single-stat') && graphDataHasMetrics" :graph-data="graphData" /> + <monitor-heatmap-chart + v-else-if="isPanelType('heatmap') && graphDataHasMetrics" + :graph-data="graphData" + :container-width="dashboardWidth" + /> <component :is="monitorChartComponent" v-else-if="graphDataHasMetrics" diff --git a/app/assets/javascripts/monitoring/components/shared/prometheus_header.vue b/app/assets/javascripts/monitoring/components/shared/prometheus_header.vue new file mode 100644 index 00000000000..153c8f389db --- /dev/null +++ b/app/assets/javascripts/monitoring/components/shared/prometheus_header.vue @@ -0,0 +1,15 @@ +<script> +export default { + props: { + graphTitle: { + type: String, + required: true, + }, + }, +}; +</script> +<template> + <div class="prometheus-graph-header"> + <h5 class="prometheus-graph-title js-graph-title">{{ graphTitle }}</h5> + </div> +</template> diff --git a/app/controllers/ldap/omniauth_callbacks_controller.rb b/app/controllers/ldap/omniauth_callbacks_controller.rb index 4d8875937eb..71a88bf3395 100644 --- a/app/controllers/ldap/omniauth_callbacks_controller.rb +++ b/app/controllers/ldap/omniauth_callbacks_controller.rb @@ -4,7 +4,7 @@ class Ldap::OmniauthCallbacksController < OmniauthCallbacksController extend ::Gitlab::Utils::Override def self.define_providers! - return unless Gitlab::Auth::LDAP::Config.enabled? + return unless Gitlab::Auth::LDAP::Config.sign_in_enabled? Gitlab::Auth::LDAP::Config.available_servers.each do |server| alias_method server['provider_name'], :ldap @@ -14,6 +14,8 @@ class Ldap::OmniauthCallbacksController < OmniauthCallbacksController # We only find ourselves here # if the authentication to LDAP was successful. def ldap + return unless Gitlab::Auth::LDAP::Config.sign_in_enabled? + sign_in_user_flow(Gitlab::Auth::LDAP::User) end diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 00e3be0edfa..0007d5826ba 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -270,7 +270,13 @@ class SessionsController < Devise::SessionsController end def ldap_servers - @ldap_servers ||= Gitlab::Auth::LDAP::Config.available_servers + @ldap_servers ||= begin + if Gitlab::Auth::LDAP::Config.sign_in_enabled? + Gitlab::Auth::LDAP::Config.available_servers + else + [] + end + end end def unverified_anonymous_user? diff --git a/app/helpers/auth_helper.rb b/app/helpers/auth_helper.rb index 9e6fcf6a267..a9c4cfe7dcc 100644 --- a/app/helpers/auth_helper.rb +++ b/app/helpers/auth_helper.rb @@ -8,6 +8,10 @@ module AuthHelper Gitlab::Auth::LDAP::Config.enabled? end + def ldap_sign_in_enabled? + Gitlab::Auth::LDAP::Config.sign_in_enabled? + end + def omniauth_enabled? Gitlab::Auth.omniauth_enabled? end @@ -56,6 +60,16 @@ module AuthHelper auth_providers.select { |provider| form_based_provider?(provider) } end + def any_form_based_providers_enabled? + form_based_providers.any? { |provider| form_enabled_for_sign_in?(provider) } + end + + def form_enabled_for_sign_in?(provider) + return true unless provider.to_s.match?(LDAP_PROVIDER) + + ldap_sign_in_enabled? + end + def crowd_enabled? auth_providers.include? :crowd end diff --git a/app/views/admin/sessions/_signin_box.html.haml b/app/views/admin/sessions/_signin_box.html.haml index 69baa76060e..1d19915d3c5 100644 --- a/app/views/admin/sessions/_signin_box.html.haml +++ b/app/views/admin/sessions/_signin_box.html.haml @@ -1,4 +1,4 @@ -- if form_based_providers.any? +- if any_form_based_providers_enabled? - if password_authentication_enabled_for_web? .login-box.tab-pane{ id: 'login-pane', role: 'tabpanel' } diff --git a/app/views/devise/sessions/new.html.haml b/app/views/devise/sessions/new.html.haml index 8f6c3ecbe58..fd6d8f3f769 100644 --- a/app/views/devise/sessions/new.html.haml +++ b/app/views/devise/sessions/new.html.haml @@ -1,13 +1,13 @@ - page_title "Sign in" #signin-container - - if form_based_providers.any? + - if any_form_based_providers_enabled? = render 'devise/shared/tabs_ldap' - else - unless experiment_enabled?(:signup_flow) = render 'devise/shared/tabs_normal' .tab-content - - if password_authentication_enabled_for_web? || ldap_enabled? || crowd_enabled? + - if password_authentication_enabled_for_web? || ldap_sign_in_enabled? || crowd_enabled? = render 'devise/shared/signin_box' -# Signup only makes sense if you can also sign-in @@ -15,7 +15,7 @@ = render 'devise/shared/signup_box' -# Show a message if none of the mechanisms above are enabled - - if !password_authentication_enabled_for_web? && !ldap_enabled? && !(omniauth_enabled? && devise_mapping.omniauthable?) + - if !password_authentication_enabled_for_web? && !ldap_sign_in_enabled? && !(omniauth_enabled? && devise_mapping.omniauthable?) %div No authentication methods configured. diff --git a/app/views/devise/shared/_signin_box.html.haml b/app/views/devise/shared/_signin_box.html.haml index 746d43edbad..6ddb7e1ac48 100644 --- a/app/views/devise/shared/_signin_box.html.haml +++ b/app/views/devise/shared/_signin_box.html.haml @@ -1,4 +1,4 @@ -- if form_based_providers.any? +- if any_form_based_providers_enabled? - if crowd_enabled? .login-box.tab-pane{ id: "crowd", role: 'tabpanel', class: active_when(form_based_auth_provider_has_active_class?(:crowd)) } .login-body diff --git a/app/views/devise/shared/_tabs_ldap.html.haml b/app/views/devise/shared/_tabs_ldap.html.haml index db54c166a53..b8f0cd2a91a 100644 --- a/app/views/devise/shared/_tabs_ldap.html.haml +++ b/app/views/devise/shared/_tabs_ldap.html.haml @@ -1,4 +1,4 @@ -%ul.nav-links.new-session-tabs.nav-tabs.nav{ class: ('custom-provider-tabs' if form_based_providers.any?) } +%ul.nav-links.new-session-tabs.nav-tabs.nav{ class: ('custom-provider-tabs' if any_form_based_providers_enabled?) } - if crowd_enabled? %li.nav-item = link_to "Crowd", "#crowd", class: "nav-link #{active_when(form_based_auth_provider_has_active_class?(:crowd))}", 'data-toggle' => 'tab' diff --git a/app/workers/stuck_ci_jobs_worker.rb b/app/workers/stuck_ci_jobs_worker.rb index 5a248ab1137..b116965d105 100644 --- a/app/workers/stuck_ci_jobs_worker.rb +++ b/app/workers/stuck_ci_jobs_worker.rb @@ -73,5 +73,19 @@ class StuckCiJobsWorker Gitlab::OptimisticLocking.retry_lock(build, 3) do |b| b.drop(reason) end + rescue => ex + build.doom! + + track_exception_for_build(ex, build) + end + + def track_exception_for_build(ex, build) + Gitlab::Sentry.track_acceptable_exception(ex, extra: { + build_id: build.id, + build_name: build.name, + build_stage: build.stage, + pipeline_id: build.pipeline_id, + project_id: build.project_id + }) end end diff --git a/changelogs/unreleased/19054-upgrade-helm.yml b/changelogs/unreleased/19054-upgrade-helm.yml new file mode 100644 index 00000000000..cb4f887a6ed --- /dev/null +++ b/changelogs/unreleased/19054-upgrade-helm.yml @@ -0,0 +1,5 @@ +--- +title: 'Updated Auto-DevOps to kubectl v1.13.12 and helm v2.15.1' +merge_request: 19054 +author: Leo Antunes +type: changed diff --git a/changelogs/unreleased/fix-stuck-ci-jobs-worker.yml b/changelogs/unreleased/fix-stuck-ci-jobs-worker.yml new file mode 100644 index 00000000000..e5e160f5743 --- /dev/null +++ b/changelogs/unreleased/fix-stuck-ci-jobs-worker.yml @@ -0,0 +1,5 @@ +--- +title: Properly handle exceptions in StuckCiJobsWorker +merge_request: 19465 +author: +type: fixed diff --git a/changelogs/unreleased/jej-prevent-ldap-sign-in.yml b/changelogs/unreleased/jej-prevent-ldap-sign-in.yml new file mode 100644 index 00000000000..cc4625d8b5a --- /dev/null +++ b/changelogs/unreleased/jej-prevent-ldap-sign-in.yml @@ -0,0 +1,5 @@ +--- +title: Add prevent_ldap_sign_in option so LDAP can be used exclusively for sync +merge_request: 18749 +author: +type: added diff --git a/changelogs/unreleased/jivanvl-add-support-heatmap-charts.yml b/changelogs/unreleased/jivanvl-add-support-heatmap-charts.yml new file mode 100644 index 00000000000..e9a13868559 --- /dev/null +++ b/changelogs/unreleased/jivanvl-add-support-heatmap-charts.yml @@ -0,0 +1,5 @@ +--- +title: Add heatmap chart support +merge_request: 32424 +author: +type: added diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 02d66067418..94fd71aaa33 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -494,6 +494,7 @@ production: &base # bundle exec rake gitlab:ldap:check RAILS_ENV=production ldap: enabled: false + prevent_ldap_sign_in: false # This setting controls the number of seconds between LDAP permission checks # for each user. After this time has expired for a given user, their next diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index 7ee4a4e3610..5e94a0716fa 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -5,6 +5,7 @@ require_relative '../smime_signature_settings' # Default settings Settings['ldap'] ||= Settingslogic.new({}) Settings.ldap['enabled'] = false if Settings.ldap['enabled'].nil? +Settings.ldap['prevent_ldap_sign_in'] = false if Settings.ldap['prevent_ldap_sign_in'].blank? Gitlab.ee do Settings.ldap['sync_time'] = 3600 if Settings.ldap['sync_time'].nil? diff --git a/config/routes/user.rb b/config/routes/user.rb index d4616c8080d..6e277f18e36 100644 --- a/config/routes/user.rb +++ b/config/routes/user.rb @@ -13,7 +13,7 @@ def override_omniauth(provider, controller, path_prefix = '/users/auth') end # Use custom controller for LDAP omniauth callback -if Gitlab::Auth::LDAP::Config.enabled? +if Gitlab::Auth::LDAP::Config.sign_in_enabled? devise_scope :user do Gitlab::Auth::LDAP::Config.available_servers.each do |server| override_omniauth(server['provider_name'], 'ldap/omniauth_callbacks') diff --git a/doc/administration/auth/ldap.md b/doc/administration/auth/ldap.md index e02ce1c0a21..d449a5a72af 100644 --- a/doc/administration/auth/ldap.md +++ b/doc/administration/auth/ldap.md @@ -118,6 +118,7 @@ LDAP users must have an email address set, regardless of whether it is used to l ```ruby gitlab_rails['ldap_enabled'] = true +gitlab_rails['prevent_ldap_sign_in'] = false gitlab_rails['ldap_servers'] = YAML.load <<-EOS # remember to close this block with 'EOS' below ## ## 'main' is the GitLab 'provider ID' of this LDAP server @@ -357,6 +358,7 @@ production: # snip... ldap: enabled: false + prevent_ldap_sign_in: false servers: ## ## 'main' is the GitLab 'provider ID' of this LDAP server @@ -493,6 +495,38 @@ the configuration option `lowercase_usernames`. By default, this configuration o 1. [Restart GitLab](../restart_gitlab.md#installations-from-source) for the changes to take effect. +## Disable LDAP web sign in + +It can be be useful to prevent using LDAP credentials through the web UI when +an alternative such as SAML is preferred. This allows LDAP to be used for group +sync, while also allowing your SAML identity provider to handle additional +checks like custom 2FA. + +When LDAP web sign in is disabled, users will not see a **LDAP** tab on the sign in page. +This does not disable [using LDAP credentials for Git access](#git-password-authentication). + +**Omnibus configuration** + +1. Edit `/etc/gitlab/gitlab.rb`: + + ```ruby + gitlab_rails['prevent_ldap_sign_in'] = true + ``` + +1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect. + +**Source configuration** + +1. Edit `config/gitlab.yaml`: + + ```yaml + production: + ldap: + prevent_ldap_sign_in: true + ``` + +1. [Restart GitLab](../restart_gitlab.md#installations-from-source) for the changes to take effect. + ## Encryption ### TLS Server Authentication diff --git a/doc/development/geo.md b/doc/development/geo.md index 446d85fceed..2fb4cc710ff 100644 --- a/doc/development/geo.md +++ b/doc/development/geo.md @@ -101,15 +101,16 @@ it's successful, we replace the main repo with the newly cloned one. ### Uploads replication File uploads are also being replicated to the **secondary** node. To -track the state of syncing, the `Geo::FileRegistry` model is used. +track the state of syncing, the `Geo::UploadRegistry` model is used. -#### File Registry +#### Upload Registry Similar to the [Project Registry](#project-registry), there is a -`Geo::FileRegistry` model that tracks the synced uploads. +`Geo::UploadRegistry` model that tracks the synced uploads. -CI Job Artifacts are synced in a similar way as uploads or LFS -objects, but they are tracked by `Geo::JobArtifactRegistry` model. +CI Job Artifacts and LFS objects are synced in a similar way as uploads, +but they are tracked by `Geo::JobArtifactRegistry`, and `Geo::LfsObjectRegistry` +models respectively. #### File Download Dispatch worker diff --git a/lib/gitlab/auth/ldap/config.rb b/lib/gitlab/auth/ldap/config.rb index eb1d0925c55..4bc0ceedae7 100644 --- a/lib/gitlab/auth/ldap/config.rb +++ b/lib/gitlab/auth/ldap/config.rb @@ -21,6 +21,14 @@ module Gitlab Gitlab.config.ldap.enabled end + def self.sign_in_enabled? + enabled? && !prevent_ldap_sign_in? + end + + def self.prevent_ldap_sign_in? + Gitlab.config.ldap.prevent_ldap_sign_in + end + def self.servers Gitlab.config.ldap['servers']&.values || [] end diff --git a/lib/gitlab/ci/templates/Jobs/DAST-Default-Branch-Deploy.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/DAST-Default-Branch-Deploy.gitlab-ci.yml index ae2ff9992f9..eff20b84e3f 100644 --- a/lib/gitlab/ci/templates/Jobs/DAST-Default-Branch-Deploy.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Jobs/DAST-Default-Branch-Deploy.gitlab-ci.yml @@ -1,5 +1,5 @@ .auto-deploy: - image: "registry.gitlab.com/gitlab-org/cluster-integration/auto-deploy-image:v0.1.0" + image: "registry.gitlab.com/gitlab-org/cluster-integration/auto-deploy-image:v0.4.0" dast_environment_deploy: extends: .auto-deploy diff --git a/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml index 6de7aace8db..a95714d5684 100644 --- a/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml @@ -1,5 +1,5 @@ .auto-deploy: - image: "registry.gitlab.com/gitlab-org/cluster-integration/auto-deploy-image:v0.3.0" + image: "registry.gitlab.com/gitlab-org/cluster-integration/auto-deploy-image:v0.4.0" review: extends: .auto-deploy diff --git a/lib/gitlab/kubernetes/helm.rb b/lib/gitlab/kubernetes/helm.rb index 16ed0cb0f8e..5762c77bb95 100644 --- a/lib/gitlab/kubernetes/helm.rb +++ b/lib/gitlab/kubernetes/helm.rb @@ -3,8 +3,8 @@ module Gitlab module Kubernetes module Helm - HELM_VERSION = '2.14.3' - KUBECTL_VERSION = '1.11.10' + HELM_VERSION = '2.15.1' + KUBECTL_VERSION = '1.13.12' NAMESPACE = 'gitlab-managed-apps' SERVICE_ACCOUNT = 'tiller' CLUSTER_ROLE_BINDING = 'tiller-admin' diff --git a/spec/controllers/ldap/omniauth_callbacks_controller_spec.rb b/spec/controllers/ldap/omniauth_callbacks_controller_spec.rb index 6d588c8f915..ceab9754617 100644 --- a/spec/controllers/ldap/omniauth_callbacks_controller_spec.rb +++ b/spec/controllers/ldap/omniauth_callbacks_controller_spec.rb @@ -11,6 +11,14 @@ describe Ldap::OmniauthCallbacksController do expect(request.env['warden']).to be_authenticated end + context 'with sign in prevented' do + let(:ldap_settings) { ldap_setting_defaults.merge(prevent_ldap_sign_in: true) } + + it 'does not allow sign in' do + expect { post provider }.to raise_error(ActionController::UrlGenerationError) + end + end + it 'respects remember me checkbox' do expect do post provider, params: { remember_me: '1' } diff --git a/spec/controllers/sessions_controller_spec.rb b/spec/controllers/sessions_controller_spec.rb index 53847e30a5c..1e47df150b4 100644 --- a/spec/controllers/sessions_controller_spec.rb +++ b/spec/controllers/sessions_controller_spec.rb @@ -4,6 +4,7 @@ require 'spec_helper' describe SessionsController do include DeviseHelpers + include LdapHelpers describe '#new' do before do @@ -35,6 +36,30 @@ describe SessionsController do end end + context 'with LDAP enabled' do + before do + stub_ldap_setting(enabled: true) + end + + it 'assigns ldap_servers' do + get(:new) + + expect(assigns[:ldap_servers].first.to_h).to include('label' => 'ldap', 'provider_name' => 'ldapmain') + end + + context 'with sign_in disabled' do + before do + stub_ldap_setting(prevent_ldap_sign_in: true) + end + + it 'assigns no ldap_servers' do + get(:new) + + expect(assigns[:ldap_servers]).to eq [] + end + end + end + describe 'tracking data' do context 'when the user is part of the experimental group' do before do diff --git a/spec/helpers/auth_helper_spec.rb b/spec/helpers/auth_helper_spec.rb index aae515def0c..cb7c670198d 100644 --- a/spec/helpers/auth_helper_spec.rb +++ b/spec/helpers/auth_helper_spec.rb @@ -54,6 +54,23 @@ describe AuthHelper do end end + describe 'any_form_based_providers_enabled?' do + before do + allow(Gitlab::Auth::LDAP::Config).to receive(:enabled?).and_return(true) + end + + it 'detects form-based providers' do + allow(helper).to receive(:auth_providers) { [:twitter, :ldapmain] } + expect(helper.any_form_based_providers_enabled?).to be(true) + end + + it 'ignores ldap providers when ldap web sign in is disabled' do + allow(helper).to receive(:auth_providers) { [:twitter, :ldapmain] } + allow(helper).to receive(:ldap_sign_in_enabled?).and_return(false) + expect(helper.any_form_based_providers_enabled?).to be(false) + end + end + describe 'enabled_button_based_providers' do before do allow(helper).to receive(:auth_providers) { [:twitter, :github] } diff --git a/spec/javascripts/monitoring/charts/heatmap_spec.js b/spec/javascripts/monitoring/charts/heatmap_spec.js new file mode 100644 index 00000000000..9a98fc6fb05 --- /dev/null +++ b/spec/javascripts/monitoring/charts/heatmap_spec.js @@ -0,0 +1,69 @@ +import { shallowMount } from '@vue/test-utils'; +import { GlHeatmap } from '@gitlab/ui/dist/charts'; +import Heatmap from '~/monitoring/components/charts/heatmap.vue'; +import { graphDataPrometheusQueryRangeMultiTrack } from '../mock_data'; + +describe('Heatmap component', () => { + let heatmapChart; + let store; + + beforeEach(() => { + heatmapChart = shallowMount(Heatmap, { + propsData: { + graphData: graphDataPrometheusQueryRangeMultiTrack, + containerWidth: 100, + }, + store, + }); + }); + + afterEach(() => { + heatmapChart.destroy(); + }); + + describe('wrapped components', () => { + describe('GitLab UI heatmap chart', () => { + let glHeatmapChart; + + beforeEach(() => { + glHeatmapChart = heatmapChart.find(GlHeatmap); + }); + + it('is a Vue instance', () => { + expect(glHeatmapChart.isVueInstance()).toBe(true); + }); + + it('should display a label on the x axis', () => { + expect(heatmapChart.vm.xAxisName).toBe(graphDataPrometheusQueryRangeMultiTrack.x_label); + }); + + it('should display a label on the y axis', () => { + expect(heatmapChart.vm.yAxisName).toBe(graphDataPrometheusQueryRangeMultiTrack.y_label); + }); + + // According to the echarts docs https://echarts.apache.org/en/option.html#series-heatmap.data + // each row of the heatmap chart is represented by an array inside another parent array + // e.g. [[0, 0, 10]], the format represents the column, the row and finally the value + // corresponding to the cell + + it('should return chartData with a length of x by y, with a length of 3 per array', () => { + const row = heatmapChart.vm.chartData[0]; + + expect(row.length).toBe(3); + expect(heatmapChart.vm.chartData.length).toBe(30); + }); + + it('returns a series of labels for the x axis', () => { + const { xAxisLabels } = heatmapChart.vm; + + expect(xAxisLabels.length).toBe(5); + }); + + it('returns a series of labels for the y axis', () => { + const { yAxisLabels } = heatmapChart.vm; + + expect(yAxisLabels.length).toBe(6); + }); + }); + }); +}); diff --git a/spec/javascripts/monitoring/mock_data.js b/spec/javascripts/monitoring/mock_data.js index 6f9a2a34ef5..4d63f91f658 100644 --- a/spec/javascripts/monitoring/mock_data.js +++ b/spec/javascripts/monitoring/mock_data.js @@ -1013,3 +1013,82 @@ export const graphDataPrometheusQueryRange = { }, ], }; + +export const graphDataPrometheusQueryRangeMultiTrack = { + title: 'Super Chart A3', + type: 'heatmap', + weight: 3, + x_label: 'Status Code', + y_label: 'Time', + metrics: [], + queries: [ + { + metricId: '1', + id: 'response_metrics_nginx_ingress_throughput_status_code', + query_range: + 'sum(rate(nginx_upstream_responses_total{upstream=~"%{kube_namespace}-%{ci_environment_slug}-.*"}[60m])) by (status_code)', + unit: 'req / sec', + label: 'Status Code', + metric_id: 1, + prometheus_endpoint_path: + '/root/rails_nodb/environments/3/prometheus/api/v1/query_range?query=sum%28rate%28nginx_upstream_responses_total%7Bupstream%3D~%22%25%7Bkube_namespace%7D-%25%7Bci_environment_slug%7D-.%2A%22%7D%5B2m%5D%29%29+by+%28status_code%29', + result: [ + { + metric: { status_code: '1xx' }, + values: [ + ['2019-08-30T15:00:00.000Z', 0], + ['2019-08-30T16:00:00.000Z', 2], + ['2019-08-30T17:00:00.000Z', 0], + ['2019-08-30T18:00:00.000Z', 0], + ['2019-08-30T19:00:00.000Z', 0], + ['2019-08-30T20:00:00.000Z', 3], + ], + }, + { + metric: { status_code: '2xx' }, + values: [ + ['2019-08-30T15:00:00.000Z', 1], + ['2019-08-30T16:00:00.000Z', 3], + ['2019-08-30T17:00:00.000Z', 6], + ['2019-08-30T18:00:00.000Z', 10], + ['2019-08-30T19:00:00.000Z', 8], + ['2019-08-30T20:00:00.000Z', 6], + ], + }, + { + metric: { status_code: '3xx' }, + values: [ + ['2019-08-30T15:00:00.000Z', 1], + ['2019-08-30T16:00:00.000Z', 2], + ['2019-08-30T17:00:00.000Z', 3], + ['2019-08-30T18:00:00.000Z', 3], + ['2019-08-30T19:00:00.000Z', 2], + ['2019-08-30T20:00:00.000Z', 1], + ], + }, + { + metric: { status_code: '4xx' }, + values: [ + ['2019-08-30T15:00:00.000Z', 2], + ['2019-08-30T16:00:00.000Z', 0], + ['2019-08-30T17:00:00.000Z', 0], + ['2019-08-30T18:00:00.000Z', 2], + ['2019-08-30T19:00:00.000Z', 0], + ['2019-08-30T20:00:00.000Z', 2], + ], + }, + { + metric: { status_code: '5xx' }, + values: [ + ['2019-08-30T15:00:00.000Z', 0], + ['2019-08-30T16:00:00.000Z', 1], + ['2019-08-30T17:00:00.000Z', 0], + ['2019-08-30T18:00:00.000Z', 0], + ['2019-08-30T19:00:00.000Z', 0], + ['2019-08-30T20:00:00.000Z', 2], + ], + }, + ], + }, + ], +}; diff --git a/spec/javascripts/monitoring/shared/prometheus_header_spec.js b/spec/javascripts/monitoring/shared/prometheus_header_spec.js new file mode 100644 index 00000000000..9f916a4dfbb --- /dev/null +++ b/spec/javascripts/monitoring/shared/prometheus_header_spec.js @@ -0,0 +1,26 @@ +import { shallowMount } from '@vue/test-utils'; +import PrometheusHeader from '~/monitoring/components/shared/prometheus_header.vue'; + +describe('Prometheus Header component', () => { + let prometheusHeader; + + beforeEach(() => { + prometheusHeader = shallowMount(PrometheusHeader, { + propsData: { + graphTitle: 'graph header', + }, + }); + }); + + afterEach(() => { + prometheusHeader.destroy(); + }); + + describe('Prometheus header component', () => { + it('should show a title', () => { + const title = prometheusHeader.vm.$el.querySelector('.js-graph-title').textContent; + + expect(title).toBe('graph header'); + }); + }); +}); diff --git a/spec/lib/gitlab/auth/ldap/config_spec.rb b/spec/lib/gitlab/auth/ldap/config_spec.rb index 577dfe51949..e4a90d4018d 100644 --- a/spec/lib/gitlab/auth/ldap/config_spec.rb +++ b/spec/lib/gitlab/auth/ldap/config_spec.rb @@ -535,4 +535,23 @@ AtlErSqafbECNDSwS5BX8yDpu5yRBJ4xegO/rNlmb8ICRYkuJapD1xXicFOsmfUK end end end + + describe 'sign_in_enabled?' do + using RSpec::Parameterized::TableSyntax + + where(:enabled, :prevent_ldap_sign_in, :result) do + true | false | true + 'true' | false | true + true | true | false + false | nil | false + end + + with_them do + it do + stub_ldap_setting(enabled: enabled, prevent_ldap_sign_in: prevent_ldap_sign_in) + + expect(described_class.sign_in_enabled?).to eq(result) + end + end + end end diff --git a/spec/lib/gitlab/kubernetes/helm/pod_spec.rb b/spec/lib/gitlab/kubernetes/helm/pod_spec.rb index 64cadcc011c..0bba9d6e858 100644 --- a/spec/lib/gitlab/kubernetes/helm/pod_spec.rb +++ b/spec/lib/gitlab/kubernetes/helm/pod_spec.rb @@ -30,7 +30,7 @@ describe Gitlab::Kubernetes::Helm::Pod do it 'generates the appropriate specifications for the container' do container = subject.generate.spec.containers.first expect(container.name).to eq('helm') - expect(container.image).to eq('registry.gitlab.com/gitlab-org/cluster-integration/helm-install-image/releases/2.14.3-kube-1.11.10') + expect(container.image).to eq('registry.gitlab.com/gitlab-org/cluster-integration/helm-install-image/releases/2.15.1-kube-1.13.12') expect(container.env.count).to eq(3) expect(container.env.map(&:name)).to match_array([:HELM_VERSION, :TILLER_NAMESPACE, :COMMAND_SCRIPT]) expect(container.command).to match_array(["/bin/sh"]) diff --git a/spec/routing/routing_spec.rb b/spec/routing/routing_spec.rb index e8333232b90..6f67cdb1222 100644 --- a/spec/routing/routing_spec.rb +++ b/spec/routing/routing_spec.rb @@ -277,6 +277,33 @@ describe "Authentication", "routing" do it "PUT /users/password" do expect(put("/users/password")).to route_to('passwords#update') end + + context 'with LDAP configured' do + include LdapHelpers + + let(:ldap_settings) { { enabled: true } } + + before do + stub_ldap_setting(ldap_settings) + Rails.application.reload_routes! + end + + after(:all) do + Rails.application.reload_routes! + end + + it 'POST /users/auth/ldapmain/callback' do + expect(post("/users/auth/ldapmain/callback")).to route_to('ldap/omniauth_callbacks#ldapmain') + end + + context 'with LDAP sign-in disabled' do + let(:ldap_settings) { { enabled: true, prevent_ldap_sign_in: true } } + + it 'prevents POST /users/auth/ldapmain/callback' do + expect(post("/users/auth/ldapmain/callback")).not_to be_routable + end + end + end end describe HealthCheckController, 'routing' do diff --git a/spec/support/controllers/ldap_omniauth_callbacks_controller_shared_context.rb b/spec/support/controllers/ldap_omniauth_callbacks_controller_shared_context.rb index d636c1cf6cd..8a8a2f714bc 100644 --- a/spec/support/controllers/ldap_omniauth_callbacks_controller_shared_context.rb +++ b/spec/support/controllers/ldap_omniauth_callbacks_controller_shared_context.rb @@ -10,6 +10,8 @@ shared_context 'Ldap::OmniauthCallbacksController' do let(:provider) { 'ldapmain' } let(:valid_login?) { true } let(:user) { create(:omniauth_user, extern_uid: uid, provider: provider) } + let(:ldap_setting_defaults) { { enabled: true, servers: ldap_server_config } } + let(:ldap_settings) { ldap_setting_defaults } let(:ldap_server_config) do { main: ldap_config_defaults(:main) } end @@ -23,7 +25,7 @@ shared_context 'Ldap::OmniauthCallbacksController' do end before do - stub_ldap_setting(enabled: true, servers: ldap_server_config) + stub_ldap_setting(ldap_settings) described_class.define_providers! Rails.application.reload_routes! @@ -36,4 +38,8 @@ shared_context 'Ldap::OmniauthCallbacksController' do after do Rails.application.env_config['omniauth.auth'] = @original_env_config_omniauth_auth end + + after(:all) do + Rails.application.reload_routes! + end end diff --git a/spec/views/devise/sessions/new.html.haml_spec.rb b/spec/views/devise/sessions/new.html.haml_spec.rb new file mode 100644 index 00000000000..66afc2af7ce --- /dev/null +++ b/spec/views/devise/sessions/new.html.haml_spec.rb @@ -0,0 +1,71 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'devise/sessions/new' do + describe 'ldap' do + include LdapHelpers + + let(:server) { { provider_name: 'ldapmain', label: 'LDAP' }.with_indifferent_access } + + before do + enable_ldap + stub_devise + disable_captcha + disable_sign_up + disable_other_signin_methods + + allow(view).to receive(:experiment_enabled?).and_return(false) + end + + it 'is shown when enabled' do + render + + expect(rendered).to have_selector('.new-session-tabs') + expect(rendered).to have_selector('[data-qa-selector="ldap_tab"]') + expect(rendered).to have_field('LDAP Username') + end + + it 'is not shown when LDAP sign in is disabled' do + disable_ldap_sign_in + + render + + expect(rendered).to have_content('No authentication methods configured') + expect(rendered).not_to have_selector('[data-qa-selector="ldap_tab"]') + expect(rendered).not_to have_field('LDAP Username') + end + end + + def disable_other_signin_methods + allow(view).to receive(:password_authentication_enabled_for_web?).and_return(false) + allow(view).to receive(:omniauth_enabled?).and_return(false) + end + + def disable_sign_up + allow(view).to receive(:allow_signup?).and_return(false) + end + + def stub_devise + allow(view).to receive(:devise_mapping).and_return(Devise.mappings[:user]) + allow(view).to receive(:resource).and_return(spy) + allow(view).to receive(:resource_name).and_return(:user) + end + + def enable_ldap + stub_ldap_setting(enabled: true) + assign(:ldap_servers, [server]) + allow(view).to receive(:form_based_providers).and_return([:ldapmain]) + allow(view).to receive(:omniauth_callback_path).with(:user, 'ldapmain').and_return('/ldapmain') + end + + def disable_ldap_sign_in + allow(view).to receive(:ldap_sign_in_enabled?).and_return(false) + assign(:ldap_servers, []) + end + + def disable_captcha + allow(view).to receive(:captcha_enabled?).and_return(false) + allow(view).to receive(:captcha_on_login_required?).and_return(false) + end +end diff --git a/spec/workers/stuck_ci_jobs_worker_spec.rb b/spec/workers/stuck_ci_jobs_worker_spec.rb index c3d577e2dae..59707409b5a 100644 --- a/spec/workers/stuck_ci_jobs_worker_spec.rb +++ b/spec/workers/stuck_ci_jobs_worker_spec.rb @@ -18,15 +18,30 @@ describe StuckCiJobsWorker do end shared_examples 'job is dropped' do - before do + it "changes status" do worker.perform job.reload - end - it "changes status" do expect(job).to be_failed expect(job).to be_stuck_or_timeout_failure end + + context 'when job have data integrity problem' do + it "does drop the job and logs the reason" do + job.update_columns(yaml_variables: '[{"key" => "value"}]') + + expect(Gitlab::Sentry).to receive(:track_acceptable_exception) + .with(anything, a_hash_including(extra: a_hash_including(build_id: job.id))) + .once + .and_call_original + + worker.perform + job.reload + + expect(job).to be_failed + expect(job).to be_data_integrity_failure + end + end end shared_examples 'job is unchanged' do |