Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2020-01-07 12:07:55 +00:00
parent e440c86979
commit 05f1d5d981
32 changed files with 297 additions and 146 deletions

View File

@ -10,7 +10,6 @@ stages:
- review - review
- qa - qa
- post-qa - post-qa
- notification
- pages - pages
variables: variables:
@ -36,7 +35,6 @@ include:
- local: .gitlab/ci/frontend.gitlab-ci.yml - local: .gitlab/ci/frontend.gitlab-ci.yml
- local: .gitlab/ci/global.gitlab-ci.yml - local: .gitlab/ci/global.gitlab-ci.yml
- local: .gitlab/ci/memory.gitlab-ci.yml - local: .gitlab/ci/memory.gitlab-ci.yml
- local: .gitlab/ci/notifications.gitlab-ci.yml
- local: .gitlab/ci/pages.gitlab-ci.yml - local: .gitlab/ci/pages.gitlab-ci.yml
- local: .gitlab/ci/qa.gitlab-ci.yml - local: .gitlab/ci/qa.gitlab-ci.yml
- local: .gitlab/ci/reports.gitlab-ci.yml - local: .gitlab/ci/reports.gitlab-ci.yml

View File

@ -1,27 +0,0 @@
# Make sure to update all the similar conditions in other CI config files if you modify these conditions
.if-canonical-gitlab-schedule: &if-canonical-gitlab-schedule
if: '$CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE =~ /^gitlab-org($|\/)/ && $CI_PIPELINE_SOURCE == "schedule"'
.notify:
image: ruby:2.6-alpine
stage: notification
dependencies: []
cache: {}
before_script:
- apk update && apk add git curl bash
- source scripts/utils.sh
- source scripts/notifications.sh
- install_gitlab_gem
variables:
COMMIT_NOTES_URL: "https://${CI_SERVER_HOST}/${CI_PROJECT_PATH}/commit/${CI_COMMIT_SHA}#notes-list"
package-and-qa:notify-failure:
extends: .notify
rules:
- <<: *if-canonical-gitlab-schedule
when: manual # TODO: remove notify job if not necessary
script:
- 'export NOTIFICATION_MESSAGE=":skull_and_crossbones: Scheduled QA against master failed! :skull_and_crossbones: See ${CI_PIPELINE_URL}. For downstream pipelines, see ${COMMIT_NOTES_URL}"'
- 'notify_on_job_failure package-and-qa qa-master "${NOTIFICATION_MESSAGE}" ci_failing'
needs: ["package-and-qa"]
allow_failure: true

View File

@ -1 +1 @@
1.78.0 1.79.0

View File

@ -53,6 +53,7 @@ export default class Clusters {
helpPath, helpPath,
ingressHelpPath, ingressHelpPath,
ingressDnsHelpPath, ingressDnsHelpPath,
ingressModSecurityHelpPath,
environmentsHelpPath, environmentsHelpPath,
clustersHelpPath, clustersHelpPath,
deployBoardsHelpPath, deployBoardsHelpPath,
@ -69,6 +70,7 @@ export default class Clusters {
helpPath, helpPath,
ingressHelpPath, ingressHelpPath,
ingressDnsHelpPath, ingressDnsHelpPath,
ingressModSecurityHelpPath,
environmentsHelpPath, environmentsHelpPath,
clustersHelpPath, clustersHelpPath,
deployBoardsHelpPath, deployBoardsHelpPath,
@ -169,6 +171,7 @@ export default class Clusters {
ingressHelpPath: this.state.ingressHelpPath, ingressHelpPath: this.state.ingressHelpPath,
managePrometheusPath: this.state.managePrometheusPath, managePrometheusPath: this.state.managePrometheusPath,
ingressDnsHelpPath: this.state.ingressDnsHelpPath, ingressDnsHelpPath: this.state.ingressDnsHelpPath,
ingressModSecurityHelpPath: this.state.ingressModSecurityHelpPath,
cloudRunHelpPath: this.state.cloudRunHelpPath, cloudRunHelpPath: this.state.cloudRunHelpPath,
providerType: this.state.providerType, providerType: this.state.providerType,
preInstalledKnative: this.state.preInstalledKnative, preInstalledKnative: this.state.preInstalledKnative,

View File

@ -56,6 +56,11 @@ export default {
required: false, required: false,
default: '', default: '',
}, },
ingressModSecurityHelpPath: {
type: String,
required: false,
default: '',
},
cloudRunHelpPath: { cloudRunHelpPath: {
type: String, type: String,
required: false, required: false,
@ -112,6 +117,9 @@ export default {
ingressInstalled() { ingressInstalled() {
return this.applications.ingress.status === APPLICATION_STATUS.INSTALLED; return this.applications.ingress.status === APPLICATION_STATUS.INSTALLED;
}, },
ingressEnableModsecurity() {
return this.applications.ingress.modsecurity_enabled;
},
ingressExternalEndpoint() { ingressExternalEndpoint() {
return this.applications.ingress.externalIp || this.applications.ingress.externalHostname; return this.applications.ingress.externalIp || this.applications.ingress.externalHostname;
}, },
@ -127,6 +135,18 @@ export default {
enableClusterApplicationElasticStack() { enableClusterApplicationElasticStack() {
return gon.features && gon.features.enableClusterApplicationElasticStack; return gon.features && gon.features.enableClusterApplicationElasticStack;
}, },
ingressModSecurityDescription() {
const escapedUrl = _.escape(this.ingressModSecurityHelpPath);
return sprintf(
s__('ClusterIntegration|Learn more about %{startLink}ModSecurity%{endLink}'),
{
startLink: `<a href="${escapedUrl}" target="_blank" rel="noopener noreferrer">`,
endLink: '</a>',
},
false,
);
},
ingressDescription() { ingressDescription() {
return sprintf( return sprintf(
_.escape( _.escape(
@ -135,9 +155,9 @@ export default {
), ),
), ),
{ {
pricingLink: `<strong><a href="https://cloud.google.com/compute/pricing#lb" pricingLink: `<a href="https://cloud.google.com/compute/pricing#lb"
target="_blank" rel="noopener noreferrer"> target="_blank" rel="noopener noreferrer">
${_.escape(s__('ClusterIntegration|pricing'))}</a></strong>`, ${_.escape(s__('ClusterIntegration|pricing'))}</a>`,
}, },
false, false,
); );
@ -311,6 +331,9 @@ Crossplane runs inside your Kubernetes cluster and supports secure connectivity
:request-reason="applications.ingress.requestReason" :request-reason="applications.ingress.requestReason"
:installed="applications.ingress.installed" :installed="applications.ingress.installed"
:install-failed="applications.ingress.installFailed" :install-failed="applications.ingress.installFailed"
:install-application-request-params="{
modsecurity_enabled: applications.ingress.modsecurity_enabled,
}"
:uninstallable="applications.ingress.uninstallable" :uninstallable="applications.ingress.uninstallable"
:uninstall-successful="applications.ingress.uninstallSuccessful" :uninstall-successful="applications.ingress.uninstallSuccessful"
:uninstall-failed="applications.ingress.uninstallFailed" :uninstall-failed="applications.ingress.uninstallFailed"
@ -326,6 +349,26 @@ Crossplane runs inside your Kubernetes cluster and supports secure connectivity
}} }}
</p> </p>
<template>
<div class="form-group">
<div class="form-check form-check-inline">
<input
v-model="applications.ingress.modsecurity_enabled"
:disabled="ingressInstalled"
type="checkbox"
autocomplete="off"
class="form-check-input"
/>
<label class="form-check-label label-bold" for="ingress-enable-modsecurity">
{{ s__('ClusterIntegration|Enable Web Application Firewall') }}
</label>
</div>
<p class="form-text text-muted">
<strong v-html="ingressModSecurityDescription"></strong>
</p>
</div>
</template>
<template v-if="ingressInstalled"> <template v-if="ingressInstalled">
<div class="form-group"> <div class="form-group">
<label for="ingress-endpoint">{{ s__('ClusterIntegration|Ingress Endpoint') }}</label> <label for="ingress-endpoint">{{ s__('ClusterIntegration|Ingress Endpoint') }}</label>
@ -375,7 +418,9 @@ Crossplane runs inside your Kubernetes cluster and supports secure connectivity
</p> </p>
</template> </template>
<template v-if="!ingressInstalled"> <template v-if="!ingressInstalled">
<div class="bs-callout bs-callout-info" v-html="ingressDescription"></div> <div class="bs-callout bs-callout-info">
<strong v-html="ingressDescription"></strong>
</div>
</template> </template>
</div> </div>
</application-row> </application-row>

View File

@ -52,6 +52,7 @@ export default class ClusterStore {
ingress: { ingress: {
...applicationInitialState, ...applicationInitialState,
title: s__('ClusterIntegration|Ingress'), title: s__('ClusterIntegration|Ingress'),
modsecurity_enabled: false,
externalIp: null, externalIp: null,
externalHostname: null, externalHostname: null,
}, },
@ -108,6 +109,7 @@ export default class ClusterStore {
helpPath, helpPath,
ingressHelpPath, ingressHelpPath,
ingressDnsHelpPath, ingressDnsHelpPath,
ingressModSecurityHelpPath,
environmentsHelpPath, environmentsHelpPath,
clustersHelpPath, clustersHelpPath,
deployBoardsHelpPath, deployBoardsHelpPath,
@ -116,6 +118,7 @@ export default class ClusterStore {
this.state.helpPath = helpPath; this.state.helpPath = helpPath;
this.state.ingressHelpPath = ingressHelpPath; this.state.ingressHelpPath = ingressHelpPath;
this.state.ingressDnsHelpPath = ingressDnsHelpPath; this.state.ingressDnsHelpPath = ingressDnsHelpPath;
this.state.ingressModSecurityHelpPath = ingressModSecurityHelpPath;
this.state.environmentsHelpPath = environmentsHelpPath; this.state.environmentsHelpPath = environmentsHelpPath;
this.state.clustersHelpPath = clustersHelpPath; this.state.clustersHelpPath = clustersHelpPath;
this.state.deployBoardsHelpPath = deployBoardsHelpPath; this.state.deployBoardsHelpPath = deployBoardsHelpPath;
@ -207,6 +210,8 @@ export default class ClusterStore {
if (appId === INGRESS) { if (appId === INGRESS) {
this.state.applications.ingress.externalIp = serverAppEntry.external_ip; this.state.applications.ingress.externalIp = serverAppEntry.external_ip;
this.state.applications.ingress.externalHostname = serverAppEntry.external_hostname; this.state.applications.ingress.externalHostname = serverAppEntry.external_hostname;
this.state.applications.ingress.modsecurity_enabled =
serverAppEntry.modsecurity_enabled || this.state.applications.ingress.modsecurity_enabled;
} else if (appId === CERT_MANAGER) { } else if (appId === CERT_MANAGER) {
this.state.applications.cert_manager.email = this.state.applications.cert_manager.email =
this.state.applications.cert_manager.email || serverAppEntry.email; this.state.applications.cert_manager.email || serverAppEntry.email;

View File

@ -47,7 +47,7 @@ class Clusters::ApplicationsController < Clusters::BaseController
end end
def cluster_application_params def cluster_application_params
params.permit(:application, :hostname, :kibana_hostname, :email, :stack) params.permit(:application, :hostname, :kibana_hostname, :email, :stack, :modsecurity_enabled)
end end
def cluster_application_destroy_params def cluster_application_destroy_params

View File

@ -14,6 +14,7 @@ module Clusters
include AfterCommitQueue include AfterCommitQueue
default_value_for :ingress_type, :nginx default_value_for :ingress_type, :nginx
default_value_for :modsecurity_enabled, false
default_value_for :version, VERSION default_value_for :version, VERSION
enum ingress_type: { enum ingress_type: {
@ -73,7 +74,7 @@ module Clusters
private private
def specification def specification
return {} unless Feature.enabled?(:ingress_modsecurity) return {} unless modsecurity_enabled
{ {
"controller" => { "controller" => {

View File

@ -11,6 +11,7 @@ class ClusterApplicationEntity < Grape::Entity
expose :kibana_hostname, if: -> (e, _) { e.respond_to?(:kibana_hostname) } expose :kibana_hostname, if: -> (e, _) { e.respond_to?(:kibana_hostname) }
expose :email, if: -> (e, _) { e.respond_to?(:email) } expose :email, if: -> (e, _) { e.respond_to?(:email) }
expose :stack, if: -> (e, _) { e.respond_to?(:stack) } expose :stack, if: -> (e, _) { e.respond_to?(:stack) }
expose :modsecurity_enabled, if: -> (e, _) { e.respond_to?(:modsecurity_enabled) }
expose :update_available?, as: :update_available, if: -> (e, _) { e.respond_to?(:update_available?) } expose :update_available?, as: :update_available, if: -> (e, _) { e.respond_to?(:update_available?) }
expose :can_uninstall?, as: :can_uninstall expose :can_uninstall?, as: :can_uninstall
end end

View File

@ -31,6 +31,10 @@ module Clusters
application.stack = params[:stack] application.stack = params[:stack]
end end
if application.has_attribute?(:modsecurity_enabled)
application.modsecurity_enabled = params[:modsecurity_enabled] || false
end
if application.respond_to?(:oauth_application) if application.respond_to?(:oauth_application)
application.oauth_application = create_oauth_application(application, request) application.oauth_application = create_oauth_application(application, request)
end end

View File

@ -30,6 +30,7 @@
help_path: help_page_path('user/project/clusters/index.md', anchor: 'installing-applications'), help_path: help_page_path('user/project/clusters/index.md', anchor: 'installing-applications'),
ingress_help_path: help_page_path('user/project/clusters/index.md', anchor: 'getting-the-external-endpoint'), ingress_help_path: help_page_path('user/project/clusters/index.md', anchor: 'getting-the-external-endpoint'),
ingress_dns_help_path: help_page_path('user/project/clusters/index.md', anchor: 'manually-determining-the-external-endpoint'), ingress_dns_help_path: help_page_path('user/project/clusters/index.md', anchor: 'manually-determining-the-external-endpoint'),
ingress_mod_security_help_path: help_page_path('user/clusters/applications.md', anchor: 'web-application-firewall-modsecurity'),
environments_help_path: help_page_path('ci/environments', anchor: 'defining-environments'), environments_help_path: help_page_path('ci/environments', anchor: 'defining-environments'),
clusters_help_path: help_page_path('user/project/clusters/index.md', anchor: 'deploying-to-a-kubernetes-cluster'), clusters_help_path: help_page_path('user/project/clusters/index.md', anchor: 'deploying-to-a-kubernetes-cluster'),
deploy_boards_help_path: help_page_path('user/project/deploy_boards.html', anchor: 'enabling-deploy-boards'), deploy_boards_help_path: help_page_path('user/project/deploy_boards.html', anchor: 'enabling-deploy-boards'),

View File

@ -187,3 +187,4 @@
- project_daily_statistics - project_daily_statistics
- create_evidence - create_evidence
- group_export - group_export
- self_monitoring_project_create

View File

@ -0,0 +1,40 @@
# frozen_string_literal: true
class SelfMonitoringProjectCreateWorker
include ApplicationWorker
include ExclusiveLeaseGuard
# This worker falls under Self-monitoring with Monitor::APM group. However,
# self-monitoring is not classified as a feature category but rather as
# Other Functionality. Metrics seems to be the closest feature_category for
# this worker.
feature_category :metrics
LEASE_TIMEOUT = 15.minutes.to_i
EXCLUSIVE_LEASE_KEY = 'self_monitoring_service_creation_deletion'
def perform
try_obtain_lease do
Gitlab::DatabaseImporters::SelfMonitoring::Project::CreateService.new.execute
end
end
# @param job_id [String]
# Job ID that is used to construct the cache keys.
# @return [Hash]
# Returns true if the job is enqueued or in progress and false otherwise.
def self.in_progress?(job_id)
Gitlab::SidekiqStatus.job_status(Array.wrap(job_id)).first
end
private
def lease_key
EXCLUSIVE_LEASE_KEY
end
def lease_timeout
LEASE_TIMEOUT
end
end

View File

@ -0,0 +1,5 @@
---
title: Add enable_modsecurity setting to managed ingress
merge_request: 21966
author:
type: added

View File

@ -0,0 +1,5 @@
---
title: Upgrade to Gitaly v1.79.0
merge_request: 22515
author:
type: changed

View File

@ -99,6 +99,7 @@
- [chaos, 2] - [chaos, 2]
- [create_evidence, 2] - [create_evidence, 2]
- [group_export, 1] - [group_export, 1]
- [self_monitoring_project_create, 2]
# EE-specific queues # EE-specific queues
- [analytics, 1] - [analytics, 1]

View File

@ -264,10 +264,6 @@ subgraph "`qa` stage"
dast -.-> |needs and depends on| G; dast -.-> |needs and depends on| G;
end end
subgraph "`notification` stage"
NOTIFICATION2["package-and-qa:notify-failure<br>(manual)"] -.-> |needs| Q;
end
subgraph "`post-test` stage" subgraph "`post-test` stage"
M M
end end

View File

@ -248,10 +248,10 @@ use an A record. If your external endpoint is a hostname, use a CNAME record.
#### Web Application Firewall (ModSecurity) #### Web Application Firewall (ModSecurity)
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/issues/65192) in GitLab 12.3 (enabled using `ingress_modsecurity` [feature flag](../../development/feature_flags/development.md#enabling-a-feature-flag-in-development)). > [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/21966) in GitLab 12.7.
Out of the box, GitLab provides you real-time security monitoring with Out of the box, GitLab provides you real-time security monitoring with
[`modsecurity`](https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#modsecurity) [ModSecurity](https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#modsecurity).
Modsecurity is a toolkit for real-time web application monitoring, logging, Modsecurity is a toolkit for real-time web application monitoring, logging,
and access control. With GitLab's offering, the [OWASP's Core Rule Set](https://www.modsecurity.org/CRS/Documentation/), which provides generic attack detection capabilities, and access control. With GitLab's offering, the [OWASP's Core Rule Set](https://www.modsecurity.org/CRS/Documentation/), which provides generic attack detection capabilities,
@ -267,22 +267,18 @@ This feature:
kubectl -n gitlab-managed-apps exec -it $(kubectl get pods -n gitlab-managed-apps | grep 'ingress-controller' | awk '{print $1}') -- tail -f /var/log/modsec/audit.log kubectl -n gitlab-managed-apps exec -it $(kubectl get pods -n gitlab-managed-apps | grep 'ingress-controller' | awk '{print $1}') -- tail -f /var/log/modsec/audit.log
``` ```
There is a small performance overhead by enabling `modsecurity`. If this is To enable ModSecurity, check the **Enable Web Application Firewall** checkbox
considered significant for your application, you can either: when installing your [Ingress application](#ingress).
- Disable ModSecurity's rule engine for your deployed application by setting There is a small performance overhead by enabling ModSecurity. If this is
[the deployment variable](../../topics/autodevops/index.md) considered significant for your application, you can disable ModSecurity's
`AUTO_DEVOPS_MODSECURITY_SEC_RULE_ENGINE` to `Off`. This will prevent ModSecurity from rule engine for your deployed application by setting
processing any requests for the given application or environment. [the deployment variable](../../topics/autodevops/index.md)
- Toggle the feature flag to false by running the following command within your `AUTO_DEVOPS_MODSECURITY_SEC_RULE_ENGINE` to `Off`. This will prevent ModSecurity
instance's Rails console: from processing any requests for the given application or environment.
```ruby To permanently disable it, you must [uninstall](#uninstalling-applications) and
Feature.disable(:ingress_modsecurity) reinstall your Ingress application for the changes to take effect.
```
Once disabled, you must [uninstall](#uninstalling-applications) and reinstall your Ingress
application for the changes to take effect.
### JupyterHub ### JupyterHub

View File

@ -0,0 +1,25 @@
# frozen_string_literal: true
module Gitlab
module DatabaseImporters
module SelfMonitoring
module Helpers
def application_settings
@application_settings ||= ApplicationSetting.current_without_cache
end
def project_created?
self_monitoring_project.present?
end
def self_monitoring_project
application_settings.instance_administration_project
end
def self_monitoring_project_id
application_settings.instance_administration_project_id
end
end
end
end
end

View File

@ -6,38 +6,26 @@ module Gitlab
module Project module Project
class CreateService < ::BaseService class CreateService < ::BaseService
include Stepable include Stepable
include SelfMonitoring::Helpers
STEPS_ALLOWED_TO_FAIL = [
:validate_application_settings, :validate_project_created, :validate_admins
].freeze
VISIBILITY_LEVEL = Gitlab::VisibilityLevel::INTERNAL VISIBILITY_LEVEL = Gitlab::VisibilityLevel::INTERNAL
PROJECT_NAME = 'GitLab Instance Administration' PROJECT_NAME = 'GitLab Instance Administration'
steps :validate_application_settings, steps :validate_application_settings,
:validate_project_created,
:validate_admins, :validate_admins,
:create_group, :create_group,
:create_project, :create_project,
:save_project_id, :save_project_id,
:add_group_members, :add_group_members,
:add_prometheus_manual_configuration :add_prometheus_manual_configuration,
:track_event
def initialize def initialize
super(nil) super(nil)
end end
def execute! def execute
result = execute_steps execute_steps
if result[:status] == :success
::Gitlab::Tracking.event("self_monitoring", "project_created")
result
elsif STEPS_ALLOWED_TO_FAIL.include?(result[:last_step])
::Gitlab::Tracking.event("self_monitoring", "project_created")
success
else
raise StandardError, result[:message]
end
end end
private private
@ -49,13 +37,6 @@ module Gitlab
error(_('No application_settings found')) error(_('No application_settings found'))
end end
def validate_project_created(result)
return success(result) unless project_created?
log_error('Project already created')
error(_('Project already created'))
end
def validate_admins(result) def validate_admins(result)
unless instance_admins.any? unless instance_admins.any?
log_error('No active admin user found') log_error('No active admin user found')
@ -68,7 +49,7 @@ module Gitlab
def create_group(result) def create_group(result)
if project_created? if project_created?
log_info(_('Instance administrators group already exists')) log_info(_('Instance administrators group already exists'))
result[:group] = application_settings.instance_administration_project.owner result[:group] = self_monitoring_project.owner
return success(result) return success(result)
end end
@ -84,7 +65,7 @@ module Gitlab
def create_project(result) def create_project(result)
if project_created? if project_created?
log_info('Instance administration project already exists') log_info('Instance administration project already exists')
result[:project] = application_settings.instance_administration_project result[:project] = self_monitoring_project
return success(result) return success(result)
end end
@ -99,7 +80,7 @@ module Gitlab
end end
def save_project_id(result) def save_project_id(result)
return success if project_created? return success(result) if project_created?
response = application_settings.update( response = application_settings.update(
instance_administration_project_id: result[:project].id instance_administration_project_id: result[:project].id
@ -140,12 +121,10 @@ module Gitlab
success(result) success(result)
end end
def application_settings def track_event(result)
@application_settings ||= ApplicationSetting.current_without_cache ::Gitlab::Tracking.event("self_monitoring", "project_created")
end
def project_created? success(result)
application_settings.instance_administration_project.present?
end end
def parse_url(uri_string) def parse_url(uri_string)

View File

@ -2567,6 +2567,9 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo." msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr "" msgstr ""
msgid "Batch operations"
msgstr ""
msgid "BatchComments|Delete all pending comments" msgid "BatchComments|Delete all pending comments"
msgstr "" msgstr ""
@ -3848,6 +3851,9 @@ msgstr ""
msgid "ClusterIntegration|Enable Cloud Run on GKE (beta)" msgid "ClusterIntegration|Enable Cloud Run on GKE (beta)"
msgstr "" msgstr ""
msgid "ClusterIntegration|Enable Web Application Firewall"
msgstr ""
msgid "ClusterIntegration|Enable or disable GitLab's connection to your Kubernetes cluster." msgid "ClusterIntegration|Enable or disable GitLab's connection to your Kubernetes cluster."
msgstr "" msgstr ""
@ -4034,6 +4040,9 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}." msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr "" msgstr ""
msgid "ClusterIntegration|Learn more about %{startLink}ModSecurity%{endLink}"
msgstr ""
msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}." msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
msgstr "" msgstr ""
@ -13827,9 +13836,6 @@ msgstr ""
msgid "Project access must be granted explicitly to each user." msgid "Project access must be granted explicitly to each user."
msgstr "" msgstr ""
msgid "Project already created"
msgstr ""
msgid "Project already deleted" msgid "Project already deleted"
msgstr "" msgstr ""
@ -15434,6 +15440,12 @@ msgstr ""
msgid "Resume replication" msgid "Resume replication"
msgstr "" msgstr ""
msgid "Resync"
msgstr ""
msgid "Resync all designs"
msgstr ""
msgid "Retry" msgid "Retry"
msgstr "" msgstr ""
@ -18332,6 +18344,9 @@ msgstr ""
msgid "There was an error subscribing to this label." msgid "There was an error subscribing to this label."
msgstr "" msgstr ""
msgid "There was an error syncing the Design Repositories."
msgstr ""
msgid "There was an error trying to validate your query" msgid "There was an error trying to validate your query"
msgstr "" msgstr ""

View File

@ -1,27 +0,0 @@
# Sends Slack notification MSG to CI_SLACK_WEBHOOK_URL (which needs to be set).
# ICON_EMOJI needs to be set to an icon emoji name (without the `:` around it).
function notify_slack() {
CHANNEL=$1
MSG=$2
ICON_EMOJI=$3
if [ -z "$CHANNEL" ] || [ -z "$CI_SLACK_WEBHOOK_URL" ] || [ -z "$MSG" ] || [ -z "$ICON_EMOJI" ]; then
echo "Missing argument(s) - Use: $0 channel message icon_emoji"
echo "and set CI_SLACK_WEBHOOK_URL environment variable."
else
curl -X POST --data-urlencode 'payload={"channel": "#'"${CHANNEL}"'", "username": "GitLab QA Bot", "text": "'"${MSG}"'", "icon_emoji": "'":${ICON_EMOJI}:"'"}' "${CI_SLACK_WEBHOOK_URL}"
fi
}
function notify_on_job_failure() {
JOB_NAME=$1
CHANNEL=$2
MSG=$3
ICON_EMOJI=$4
local job_id
job_id=$(scripts/get-job-id "$CI_PROJECT_ID" "$CI_PIPELINE_ID" "$JOB_NAME" -s failed)
if [ -n "${job_id}" ]; then
notify_slack "${CHANNEL}" "${MSG}" "${ICON_EMOJI}"
fi
}

View File

@ -71,6 +71,7 @@ FactoryBot.define do
end end
factory :clusters_applications_ingress, class: Clusters::Applications::Ingress do factory :clusters_applications_ingress, class: Clusters::Applications::Ingress do
modsecurity_enabled { false }
cluster factory: %i(cluster with_installed_helm provided_by_gcp) cluster factory: %i(cluster with_installed_helm provided_by_gcp)
end end

View File

@ -38,6 +38,7 @@
"kibana_hostname": { "type": ["string", "null"] }, "kibana_hostname": { "type": ["string", "null"] },
"email": { "type": ["string", "null"] }, "email": { "type": ["string", "null"] },
"stack": { "type": ["string", "null"] }, "stack": { "type": ["string", "null"] },
"modsecurity_enabled": { "type": ["boolean", "null"] },
"update_available": { "type": ["boolean", "null"] }, "update_available": { "type": ["boolean", "null"] },
"can_uninstall": { "type": "boolean" } "can_uninstall": { "type": "boolean" }
}, },

View File

@ -190,6 +190,7 @@ describe('Applications', () => {
title: 'Ingress', title: 'Ingress',
status: 'installed', status: 'installed',
externalHostname: 'localhost.localdomain', externalHostname: 'localhost.localdomain',
modsecurity_enabled: false,
}, },
helm: { title: 'Helm Tiller' }, helm: { title: 'Helm Tiller' },
cert_manager: { title: 'Cert-Manager' }, cert_manager: { title: 'Cert-Manager' },
@ -473,7 +474,12 @@ describe('Applications', () => {
vm = mountComponent(Applications, { vm = mountComponent(Applications, {
applications: { applications: {
...APPLICATIONS_MOCK_STATE, ...APPLICATIONS_MOCK_STATE,
ingress: { title: 'Ingress', status: 'installed', externalIp: '1.1.1.1' }, ingress: {
title: 'Ingress',
status: 'installed',
externalIp: '1.1.1.1',
modsecurity_enabled: false,
},
elastic_stack: { title: 'Elastic Stack', status: 'installed', kibana_hostname: '' }, elastic_stack: { title: 'Elastic Stack', status: 'installed', kibana_hostname: '' },
}, },
}); });

View File

@ -150,7 +150,7 @@ const DEFAULT_APPLICATION_STATE = {
const APPLICATIONS_MOCK_STATE = { const APPLICATIONS_MOCK_STATE = {
helm: { title: 'Helm Tiller', status: 'installable' }, helm: { title: 'Helm Tiller', status: 'installable' },
ingress: { title: 'Ingress', status: 'installable' }, ingress: { title: 'Ingress', status: 'installable', modsecurity_enabled: false },
crossplane: { title: 'Crossplane', status: 'installable', stack: '' }, crossplane: { title: 'Crossplane', status: 'installable', stack: '' },
cert_manager: { title: 'Cert-Manager', status: 'installable' }, cert_manager: { title: 'Cert-Manager', status: 'installable' },
runner: { title: 'GitLab Runner' }, runner: { title: 'GitLab Runner' },

View File

@ -86,6 +86,7 @@ describe('Clusters Store', () => {
uninstallSuccessful: false, uninstallSuccessful: false,
uninstallFailed: false, uninstallFailed: false,
validationError: null, validationError: null,
modsecurity_enabled: false,
}, },
runner: { runner: {
title: 'GitLab Runner', title: 'GitLab Runner',

View File

@ -69,15 +69,17 @@ describe('Sentry Error Stack Trace', () => {
}); });
describe('Stack trace', () => { describe('Stack trace', () => {
it('should show stacktrace', () => { beforeEach(() => {
store.state.details.loadingStacktrace = false; store.state.details.loadingStacktrace = false;
});
it('should show stacktrace', () => {
mountComponent({ stubs: {} }); mountComponent({ stubs: {} });
expect(wrapper.find(GlLoadingIcon).exists()).toBe(false); expect(wrapper.find(GlLoadingIcon).exists()).toBe(false);
expect(wrapper.find(Stacktrace).exists()).toBe(true); expect(wrapper.find(Stacktrace).exists()).toBe(true);
}); });
it('should not show stacktrace if it does not exist', () => { it('should not show stacktrace if it does not exist', () => {
store.state.details.loadingStacktrace = false;
expect(wrapper.find(GlLoadingIcon).exists()).toBe(false); expect(wrapper.find(GlLoadingIcon).exists()).toBe(false);
expect(wrapper.find(Stacktrace).exists()).toBe(false); expect(wrapper.find(Stacktrace).exists()).toBe(false);
}); });

View File

@ -4,7 +4,7 @@ require 'spec_helper'
describe Gitlab::DatabaseImporters::SelfMonitoring::Project::CreateService do describe Gitlab::DatabaseImporters::SelfMonitoring::Project::CreateService do
describe '#execute' do describe '#execute' do
let(:result) { subject.execute! } let(:result) { subject.execute }
let(:prometheus_settings) do let(:prometheus_settings) do
{ {
@ -18,10 +18,12 @@ describe Gitlab::DatabaseImporters::SelfMonitoring::Project::CreateService do
end end
context 'without application_settings' do context 'without application_settings' do
it 'does not fail' do it 'returns error' do
expect(subject).to receive(:log_error).and_call_original expect(subject).to receive(:log_error).and_call_original
expect(result).to eq( expect(result).to eq(
status: :success status: :error,
message: 'No application_settings found',
last_step: :validate_application_settings
) )
expect(Project.count).to eq(0) expect(Project.count).to eq(0)
@ -36,10 +38,12 @@ describe Gitlab::DatabaseImporters::SelfMonitoring::Project::CreateService do
allow(ApplicationSetting).to receive(:current_without_cache) { application_setting } allow(ApplicationSetting).to receive(:current_without_cache) { application_setting }
end end
it 'does not fail' do it 'returns error' do
expect(subject).to receive(:log_error).and_call_original expect(subject).to receive(:log_error).and_call_original
expect(result).to eq( expect(result).to eq(
status: :success status: :error,
message: 'No active admin user found',
last_step: :validate_admins
) )
expect(Project.count).to eq(0) expect(Project.count).to eq(0)
@ -47,7 +51,7 @@ describe Gitlab::DatabaseImporters::SelfMonitoring::Project::CreateService do
end end
end end
context 'with admin users' do context 'with application settings and admin users' do
let(:project) { result[:project] } let(:project) { result[:project] }
let(:group) { result[:group] } let(:group) { result[:group] }
let(:application_setting) { Gitlab::CurrentSettings.current_application_settings } let(:application_setting) { Gitlab::CurrentSettings.current_application_settings }
@ -73,6 +77,13 @@ describe Gitlab::DatabaseImporters::SelfMonitoring::Project::CreateService do
it_behaves_like 'has prometheus service', 'http://localhost:9090' it_behaves_like 'has prometheus service', 'http://localhost:9090'
it "tracks successful install" do
expect(::Gitlab::Tracking).to receive(:event)
expect(::Gitlab::Tracking).to receive(:event).with("self_monitoring", "project_created")
result
end
it 'creates group' do it 'creates group' do
expect(result[:status]).to eq(:success) expect(result[:status]).to eq(:success)
expect(group).to be_persisted expect(group).to be_persisted
@ -132,7 +143,11 @@ describe Gitlab::DatabaseImporters::SelfMonitoring::Project::CreateService do
it 'returns error when saving project ID fails' do it 'returns error when saving project ID fails' do
allow(application_setting).to receive(:save) { false } allow(application_setting).to receive(:save) { false }
expect { result }.to raise_error(StandardError, 'Could not save project ID') expect(result).to eq(
status: :error,
message: 'Could not save project ID',
last_step: :save_project_id
)
end end
context 'when project already exists' do context 'when project already exists' do
@ -149,9 +164,8 @@ describe Gitlab::DatabaseImporters::SelfMonitoring::Project::CreateService do
application_setting.instance_administration_project_id = existing_project.id application_setting.instance_administration_project_id = existing_project.id
end end
it 'does not fail' do it 'returns success' do
expect(subject).to receive(:log_error).and_call_original expect(result).to include(status: :success)
expect(result[:status]).to eq(:success)
expect(Project.count).to eq(1) expect(Project.count).to eq(1)
expect(Group.count).to eq(1) expect(Group.count).to eq(1)
@ -250,7 +264,11 @@ describe Gitlab::DatabaseImporters::SelfMonitoring::Project::CreateService do
it 'returns error' do it 'returns error' do
expect(subject).to receive(:log_error).and_call_original expect(subject).to receive(:log_error).and_call_original
expect { result }.to raise_error(StandardError, 'Could not create project') expect(result).to eq(
status: :error,
message: 'Could not create project',
last_step: :create_project
)
end end
end end
@ -261,7 +279,11 @@ describe Gitlab::DatabaseImporters::SelfMonitoring::Project::CreateService do
it 'returns error' do it 'returns error' do
expect(subject).to receive(:log_error).and_call_original expect(subject).to receive(:log_error).and_call_original
expect { result }.to raise_error(StandardError, 'Could not add admins as members') expect(result).to eq(
status: :error,
message: 'Could not add admins as members',
last_step: :add_group_members
)
end end
end end
@ -275,15 +297,13 @@ describe Gitlab::DatabaseImporters::SelfMonitoring::Project::CreateService do
it 'returns error' do it 'returns error' do
expect(subject).to receive(:log_error).and_call_original expect(subject).to receive(:log_error).and_call_original
expect { result }.to raise_error(StandardError, 'Could not save prometheus manual configuration') expect(result).to eq(
status: :error,
message: 'Could not save prometheus manual configuration',
last_step: :add_prometheus_manual_configuration
)
end end
end end
end end
it "tracks successful install" do
expect(Gitlab::Tracking).to receive(:event).with("self_monitoring", "project_created")
result
end
end end
end end

View File

@ -142,11 +142,11 @@ describe Clusters::Applications::Ingress do
let(:project) { build(:project) } let(:project) { build(:project) }
let(:cluster) { build(:cluster, projects: [project]) } let(:cluster) { build(:cluster, projects: [project]) }
context 'when ingress_modsecurity is enabled' do context 'when modsecurity_enabled is enabled' do
before do before do
stub_feature_flags(ingress_modsecurity: true)
allow(subject).to receive(:cluster).and_return(cluster) allow(subject).to receive(:cluster).and_return(cluster)
allow(subject).to receive(:modsecurity_enabled).and_return(true)
end end
it 'includes modsecurity module enablement' do it 'includes modsecurity module enablement' do
@ -173,10 +173,8 @@ describe Clusters::Applications::Ingress do
end end
end end
context 'when ingress_modsecurity is disabled' do context 'when modsecurity_enabled is disabled' do
before do before do
stub_feature_flags(ingress_modsecurity: false)
allow(subject).to receive(:cluster).and_return(cluster) allow(subject).to receive(:cluster).and_return(cluster)
end end

View File

@ -47,6 +47,33 @@ describe Clusters::Applications::CreateService do
create(:clusters_applications_helm, :installed, cluster: cluster) create(:clusters_applications_helm, :installed, cluster: cluster)
end end
context 'ingress application' do
let(:params) do
{
application: 'ingress',
modsecurity_enabled: true
}
end
before do
expect_any_instance_of(Clusters::Applications::Ingress)
.to receive(:make_scheduled!)
.and_call_original
end
it 'creates the application' do
expect do
subject
cluster.reload
end.to change(cluster, :application_ingress)
end
it 'sets modsecurity_enabled' do
expect(subject.modsecurity_enabled).to eq(true)
end
end
context 'cert manager application' do context 'cert manager application' do
let(:params) do let(:params) do
{ {

View File

@ -0,0 +1,28 @@
# frozen_string_literal: true
require 'spec_helper'
describe SelfMonitoringProjectCreateWorker do
describe '#perform' do
let(:service_class) { Gitlab::DatabaseImporters::SelfMonitoring::Project::CreateService }
let(:service) { instance_double(service_class) }
before do
allow(service_class).to receive(:new) { service }
end
it 'runs the SelfMonitoring::Project::CreateService' do
expect(service).to receive(:execute)
subject.perform
end
end
describe '.in_progress?', :clean_gitlab_redis_shared_state do
it 'returns in_progress when job is enqueued' do
jid = described_class.perform_async
expect(described_class.in_progress?(jid)).to eq(true)
end
end
end