Commit 5d1ec53b authored by GitLab Release Tools Bot's avatar GitLab Release Tools Bot

Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ee

parents 99af4d0f 962c0ce3
......@@ -8,6 +8,7 @@ require:
- rubocop-rspec
AllCops:
TargetRubyVersion: 2.5
TargetRailsVersion: 5.0
Exclude:
- 'vendor/**/*'
......@@ -187,3 +188,8 @@ Cop/InjectEnterpriseEditionModule:
Style/ReturnNil:
Enabled: true
# It isn't always safe to replace `=~` with `.match?`, especially when there are
# nil values on the left hand side
Performance/RegexpMatch:
Enabled: false
<script>
import folderMixin from 'ee_else_ce/environments/mixins/environments_folder_view_mixin';
import environmentsMixin from '../mixins/environments_mixin';
import CIPaginationMixin from '../../vue_shared/mixins/ci_pagination_api_mixin';
import StopEnvironmentModal from '../components/stop_environment_modal.vue';
......@@ -8,7 +9,7 @@ export default {
StopEnvironmentModal,
},
mixins: [environmentsMixin, CIPaginationMixin],
mixins: [environmentsMixin, CIPaginationMixin, folderMixin],
props: {
endpoint: {
......@@ -27,28 +28,6 @@ export default {
type: Boolean,
required: true,
},
// ee-only start
canaryDeploymentFeatureId: {
type: String,
required: true,
},
showCanaryDeploymentCallout: {
type: Boolean,
required: true,
},
userCalloutsPath: {
type: String,
required: true,
},
lockPromotionSvgPath: {
type: String,
required: true,
},
helpCanaryDeploymentsPath: {
type: String,
required: true,
},
// ee-only end
},
methods: {
successCallback(resp) {
......@@ -63,7 +42,8 @@ export default {
<div v-if="!isLoading" class="top-area">
<h4 class="js-folder-name environments-folder-name">
{{ s__('Environments|Environments') }} / <b>{{ folderName }}</b>
{{ s__('Environments|Environments') }} /
<b>{{ folderName }}</b>
</h4>
<tabs :tabs="tabs" scope="environments" @onChangeTab="onChangeTab" />
......
import Vue from 'vue';
import canaryCalloutMixin from 'ee_else_ce/environments/mixins/canary_callout_mixin';
import environmentsComponent from './components/environments_app.vue';
import { parseBoolean } from '../lib/utils/common_utils';
import Translate from '../vue_shared/translate';
// ee-only start
import CanaryCalloutMixin from 'ee/environments/mixins/canary_callout_mixin'; // eslint-disable-line import/order
// ee-only end
Vue.use(Translate);
export default () =>
......@@ -15,9 +12,7 @@ export default () =>
components: {
environmentsComponent,
},
// ee-only start
mixins: [CanaryCalloutMixin],
// ee-only end
mixins: [canaryCalloutMixin],
data() {
const environmentsData = document.querySelector(this.$options.el).dataset;
......@@ -39,13 +34,7 @@ export default () =>
cssContainerClass: this.cssContainerClass,
canCreateEnvironment: this.canCreateEnvironment,
canReadEnvironment: this.canReadEnvironment,
// ee-only start
canaryDeploymentFeatureId: this.canaryDeploymentFeatureId,
showCanaryDeploymentCallout: this.showCanaryDeploymentCallout,
userCalloutsPath: this.userCalloutsPath,
lockPromotionSvgPath: this.lockPromotionSvgPath,
helpCanaryDeploymentsPath: this.helpCanaryDeploymentsPath,
// ee-only end
...this.canaryCalloutProps,
},
});
},
......
export default {
computed: {
canaryCalloutProps() {},
},
};
export default {
props: {
canaryDeploymentFeatureId: {
type: String,
required: false,
default: '',
},
showCanaryDeploymentCallout: {
type: Boolean,
required: false,
default: false,
},
userCalloutsPath: {
type: String,
required: false,
default: '',
},
lockPromotionSvgPath: {
type: String,
required: false,
default: '',
},
helpCanaryDeploymentsPath: {
type: String,
required: false,
default: '',
},
},
};
......@@ -3,13 +3,13 @@
*/
import _ from 'underscore';
import Visibility from 'visibilityjs';
import EnvironmentsStore from 'ee_else_ce/environments/stores/environments_store';
import Poll from '../../lib/utils/poll';
import { getParameterByName } from '../../lib/utils/common_utils';
import { s__ } from '../../locale';
import Flash from '../../flash';
import eventHub from '../event_hub';
import EnvironmentsStore from '../stores/environments_store';
import EnvironmentsService from '../services/environments_service';
import tablePagination from '../../vue_shared/components/table_pagination.vue';
import environmentTable from '../components/environments_table.vue';
......
import { parseIntPagination, normalizeHeaders } from '~/lib/utils/common_utils';
import { setDeployBoard } from 'ee_else_ce/environments/stores/helpers';
// ee-only
import { CLUSTER_TYPE } from '~/clusters/constants';
/**
* Environments Store.
*
......@@ -74,41 +73,12 @@ export default class EnvironmentsStore {
filtered = Object.assign(filtered, env);
}
if (
filtered.size === 1 &&
filtered.rollout_status &&
filtered.cluster_type !== CLUSTER_TYPE.GROUP
) {
filtered = Object.assign({}, filtered, {
hasDeployBoard: true,
isDeployBoardVisible:
oldEnvironmentState.isDeployBoardVisible === false
? oldEnvironmentState.isDeployBoardVisible
: true,
deployBoardData:
filtered.rollout_status.status === 'found' ? filtered.rollout_status : {},
isLoadingDeployBoard: filtered.rollout_status.status === 'loading',
isEmptyDeployBoard: filtered.rollout_status.status === 'not_found',
});
}
filtered = setDeployBoard(oldEnvironmentState, filtered);
return filtered;
});
this.state.environments = filteredEnvironments;
// ee-only start
/**
* Add the canary callout banner underneath the second environment listed.
*
* If there is only one environment, then add to it underneath the first.
*/
if (this.state.environments.length >= 2) {
this.state.environments[1].showCanaryCallout = true;
} else if (this.state.environments.length === 1) {
this.state.environments[0].showCanaryCallout = true;
}
// ee-only end
return filteredEnvironments;
}
......@@ -221,27 +191,4 @@ export default class EnvironmentsStore {
return environments.filter(env => env.isFolder && env.isOpen);
}
/**
* Toggles deploy board visibility for the provided environment ID.
*
* @param {Object} environment
* @return {Array}
*/
toggleDeployBoard(environmentID) {
const environments = this.state.environments.slice();
this.state.environments = environments.map(env => {
let updated = Object.assign({}, env);
if (env.id === environmentID) {
updated = Object.assign({}, updated, {
isDeployBoardVisible: !env.isDeployBoardVisible,
});
}
return updated;
});
return this.state.environments;
}
}
/**
* Deploy boards are EE only.
*
* @param {Object} environment
* @returns {Object}
*/
// eslint-disable-next-line import/prefer-default-export
export const setDeployBoard = (oldEnvironmentState, environment) => environment;
import initGroupDetails from '../shared/group_details';
document.addEventListener('DOMContentLoaded', () => {
initGroupDetails('details');
});
/* eslint-disable no-new */
import { getPagePath } from '~/lib/utils/common_utils';
import { ACTIVE_TAB_SHARED, ACTIVE_TAB_ARCHIVED } from '~/groups/constants';
import NewGroupChild from '~/groups/new_group_child';
import notificationsDropdown from '~/notifications_dropdown';
import NotificationsForm from '~/notifications_form';
import ProjectsList from '~/projects_list';
import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
import GroupTabs from './group_tabs';
export default function initGroupDetails(actionName = 'show') {
const newGroupChildWrapper = document.querySelector('.js-new-project-subgroup');
const loadableActions = [ACTIVE_TAB_SHARED, ACTIVE_TAB_ARCHIVED];
const paths = window.location.pathname.split('/');
const subpath = paths[paths.length - 1];
let action = loadableActions.includes(subpath) ? subpath : getPagePath(1);
if (actionName && action === actionName) {
action = 'show'; // 'show' resets GroupTabs to default action through base class
}
new GroupTabs({ parentEl: '.groups-listing', action });
new ShortcutsNavigation();
new NotificationsForm();
notificationsDropdown();
new ProjectsList();
if (newGroupChildWrapper) {
new NewGroupChild(newGroupChildWrapper);
}
}
/* eslint-disable no-new */
import { getPagePath } from '~/lib/utils/common_utils';
import { ACTIVE_TAB_SHARED, ACTIVE_TAB_ARCHIVED } from '~/groups/constants';
import NewGroupChild from '~/groups/new_group_child';
import notificationsDropdown from '~/notifications_dropdown';
import NotificationsForm from '~/notifications_form';
import ProjectsList from '~/projects_list';
import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
import GroupTabs from './group_tabs';
import initGroupDetails from '../shared/group_details';
document.addEventListener('DOMContentLoaded', () => {
const newGroupChildWrapper = document.querySelector('.js-new-project-subgroup');
const loadableActions = [ACTIVE_TAB_SHARED, ACTIVE_TAB_ARCHIVED];
const paths = window.location.pathname.split('/');
const subpath = paths[paths.length - 1];
const action = loadableActions.includes(subpath) ? subpath : getPagePath(1);
new GroupTabs({ parentEl: '.groups-listing', action });
new ShortcutsNavigation();
new NotificationsForm();
notificationsDropdown();
new ProjectsList();
if (newGroupChildWrapper) {
new NewGroupChild(newGroupChildWrapper);
}
initGroupDetails();
});
......@@ -91,6 +91,7 @@ export default class UserTabs {
this.actions = Object.keys(this.loaded);
this.bindEvents();
// TODO: refactor to make this configurable via constructor params with a default value of 'show'
if (this.action === 'show') {
this.action = this.defaultAction;
}
......
<script>
import _ from 'underscore';
import stageColumnMixin from 'ee_else_ce/pipelines/mixins/stage_column_mixin';
import JobItem from './job_item.vue';
import JobGroupDropdown from './job_group_dropdown.vue';
......@@ -8,6 +9,7 @@ export default {
JobItem,
JobGroupDropdown,
},
mixins: [stageColumnMixin],
props: {
title: {
type: String,
......@@ -27,19 +29,11 @@ export default {
required: false,
default: '',
},
hasTriggeredBy: {
type: Boolean,
required: false,
default: false,
},
},
methods: {
groupId(group) {
return `ci-badge-${_.escape(group.name)}`;
},
buildConnnectorClass(index) {
return index === 0 && (!this.isFirstColumn || this.hasTriggeredBy) ? 'left-connector' : '';
},
pipelineActionRequestComplete() {
this.$emit('refreshPipelineGraph');
},
......
export default {
methods: {
clickTriggeredByPipeline() {},
clickTriggeredPipeline() {},
},
};
export default {
methods: {
buildConnnectorClass(index) {
return index === 0 && !this.isFirstColumn ? 'left-connector' : '';
},
},
};
......@@ -2,11 +2,11 @@ import Vue from 'vue';
import Flash from '~/flash';
import Translate from '~/vue_shared/translate';
import { __ } from '~/locale';
import pipelineGraph from 'ee/pipelines/components/graph/graph_component.vue';
import pipelineGraph from 'ee_else_ce/pipelines/components/graph/graph_component.vue';
import GraphEEMixin from 'ee_else_ce/pipelines/mixins/graph_pipeline_bundle_mixin';
import PipelinesMediator from './pipeline_details_mediator';
import pipelineHeader from './components/header_component.vue';
import eventHub from './event_hub';
import GraphEEMixin from 'ee/pipelines/mixins/graph_pipeline_bundle_mixin'; // eslint-disable-line import/order
Vue.use(Translate);
......
......@@ -376,6 +376,7 @@ img.emoji {
.prepend-top-default { margin-top: $gl-padding !important; }
.prepend-top-16 { margin-top: 16px; }
.prepend-top-20 { margin-top: 20px; }
.prepend-top-32 { margin-top: 32px; }
.prepend-left-4 { margin-left: 4px; }
.prepend-left-5 { margin-left: 5px; }
.prepend-left-8 { margin-left: 8px; }
......@@ -383,6 +384,7 @@ img.emoji {
.prepend-left-15 { margin-left: 15px; }
.prepend-left-default { margin-left: $gl-padding; }
.prepend-left-20 { margin-left: 20px; }
.prepend-left-32 { margin-left: 32px; }
.append-right-4 { margin-right: 4px; }
.append-right-5 { margin-right: 5px; }
.append-right-8 { margin-right: 8px; }
......@@ -390,6 +392,7 @@ img.emoji {
.append-right-15 { margin-right: 15px; }
.append-right-default { margin-right: $gl-padding; }
.append-right-20 { margin-right: 20px; }
.prepend-right-32 { margin-right: 32px; }
.append-bottom-0 { margin-bottom: 0; }
.append-bottom-4 { margin-bottom: $gl-padding-4; }
.append-bottom-5 { margin-bottom: 5px; }
......@@ -398,6 +401,7 @@ img.emoji {
.append-bottom-15 { margin-bottom: 15px; }
.append-bottom-20 { margin-bottom: 20px; }
.append-bottom-default { margin-bottom: $gl-padding; }
.prepend-bottom-32 { margin-bottom: 32px; }
.inline { display: inline-block; }
.block { display: block; }
.flex { display: flex; }
......
......@@ -693,10 +693,6 @@
}
}
.project-empty-note-panel {
border-bottom: 1px solid $border-color;
}
.project-stats,
.project-buttons {
.scrolling-tabs-container {
......
......@@ -58,11 +58,24 @@ class GroupsController < Groups::ApplicationController
def show
respond_to do |format|
format.html
format.html do
render_show_html
end
format.atom do
load_events
render layout: 'xml.atom'
render_details_view_atom
end
end
end
def details
respond_to do |format|
format.html do
render_details_html
end
format.atom do
render_details_view_atom
end
end
end
......@@ -119,6 +132,19 @@ class GroupsController < Groups::ApplicationController
protected
def render_show_html
render 'groups/show'
end
def render_details_html
render 'groups/show'
end
def render_details_view_atom
load_events
render layout: 'xml.atom', template: 'groups/show'
end
# rubocop: disable CodeReuse/ActiveRecord
def authorize_create_group!
allowed = if params[:parent_id].present?
......@@ -178,8 +204,8 @@ class GroupsController < Groups::ApplicationController
.includes(:namespace)
@events = EventCollection
.new(@projects, offset: params[:offset].to_i, filter: event_filter)
.to_a
.new(@projects, offset: params[:offset].to_i, filter: event_filter)
.to_a
Events::RenderService
.new(current_user)
......
......@@ -4,6 +4,7 @@ module GroupsHelper
def group_overview_nav_link_paths
%w[
groups#show
groups#details
groups#activity
groups#subgroups
analytics#show
......
......@@ -286,13 +286,11 @@ class MergeRequestDiff < ActiveRecord::Base
return yield(@external_diff_file) if @external_diff_file
external_diff.open do |file|
begin
@external_diff_file = file
@external_diff_file = file
yield(@external_diff_file)
ensure
@external_diff_file = nil
end
yield(@external_diff_file)
ensure
@external_diff_file = nil
end
end
......
......@@ -23,6 +23,6 @@ class MergeRequestDiffFile < ActiveRecord::Base
super
end
binary? ? content.unpack('m0').first : content
binary? ? content.unpack1('m0') : content
end
end
......@@ -1209,11 +1209,9 @@ class Project < ActiveRecord::Base
def repo_exists?
strong_memoize(:repo_exists) do
begin
repository.exists?
rescue
false
end
repository.exists?
rescue
false
end
end
......
......@@ -205,12 +205,10 @@ class JiraService < IssueTrackerService
# if any transition fails it will log the error message and stop the transition sequence
def transition_issue(issue)
jira_issue_transition_id.scan(Gitlab::Regex.jira_transition_id_regex).each do |transition_id|
begin
issue.transitions.build.save!(transition: { id: transition_id })
rescue => error
log_error("Issue transition failed", error: error.message, client_url: client_url)
return false
end
issue.transitions.build.save!(transition: { id: transition_id })
rescue => error
log_error("Issue transition failed", error: error.message, client_url: client_url)
return false
end
end
......
......@@ -265,16 +265,14 @@ class Repository
# to avoid unnecessary syncing.
def keep_around(*shas)
shas.each do |sha|
begin
next unless sha.present? && commit_by(oid: sha)
next unless sha.present? && commit_by(oid: sha)
next if kept_around?(sha)
next if kept_around?(sha)
# This will still fail if the file is corrupted (e.g. 0 bytes)
raw_repository.write_ref(keep_around_ref_name(sha), sha)
rescue Gitlab::Git::CommandError => ex
Rails.logger.error "Unable to create keep-around reference for repository #{disk_path}: #{ex}"
end
# This will still fail if the file is corrupted (e.g. 0 bytes)
raw_repository.write_ref(keep_around_ref_name(sha), sha)
rescue Gitlab::Git::CommandError => ex
Rails.logger.error "Unable to create keep-around reference for repository #{disk_path}: #{ex}"
end
end
......
......@@ -26,16 +26,14 @@ class UserInteractedProject < ActiveRecord::Base
cached_exists?(attributes) do
transaction(requires_new: true) do
begin
where(attributes).select(1).first || create!(attributes)
true # not caching the whole record here for now
rescue ActiveRecord::RecordNotUnique
# Note, above queries are not atomic and prone
# to race conditions (similar like #find_or_create!).
# In the case where we hit this, the record we want
# already exists - shortcut and return.
true
end
where(attributes).select(1).first || create!(attributes)
true # not caching the whole record here for now
rescue ActiveRecord::RecordNotUnique
# Note, above queries are not atomic and prone
# to race conditions (similar like #find_or_create!).
# In the case where we hit this, the record we want
# already exists - shortcut and return.
true
end
end
end
......
......@@ -42,11 +42,7 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
def empty_repo_statistics_anchors
[
license_anchor_data,
commits_anchor_data,
branches_anchor_data,
tags_anchor_data,
files_anchor_data
license_anchor_data
].compact.select { |item| item.is_link }
end
......@@ -55,9 +51,7 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
new_file_anchor_data,
readme_anchor_data,
changelog_anchor_data,
contribution_guide_anchor_data,
autodevops_anchor_data,
kubernetes_cluster_anchor_data
contribution_guide_anchor_data
].compact.reject { |item| item.is_link }
end
......
......@@ -9,16 +9,14 @@ class DetailedStatusEntity < Grape::Entity
expose :details_path
expose :illustration do |status|
begin
illustration = {
image: ActionController::Base.helpers.image_path(status.illustration[:image])
}
illustration = status.illustration.merge(illustration)
illustration = {
image: ActionController::Base.helpers.image_path(status.illustration[:image])
}
illustration = status.illustration.merge(illustration)
illustration
rescue NotImplementedError
# ignored
end
illustration
rescue NotImplementedError
# ignored
end
expose :favicon do |status|
......
......@@ -42,17 +42,15 @@ module Projects
def parse_response_links(objects_response)
objects_response.each_with_object([]) do |entry, link_list|
begin
link = entry.dig('actions', DOWNLOAD_ACTION, 'href')
link = entry.dig('actions', DOWNLOAD_ACTION, 'href')
raise DownloadLinkNotFound unless link
raise DownloadLinkNotFound unless link
link_list << LfsDownloadObject.new(oid: entry['oid'],
size: entry['size'],
link: add_credentials(link))
rescue DownloadLinkNotFound, Addressable::URI::InvalidURIError
log_error("Link for Lfs Object with oid #{entry['oid']} not found or invalid.")
end
link_list << LfsDownloadObject.new(oid: entry['oid'],
size: entry['size'],
link: add_credentials(link))
rescue DownloadLinkNotFound, Addressable::URI::InvalidURIError
log_error("Link for Lfs Object with oid #{entry['oid']} not found or invalid.")
end
end
......
......@@ -75,17 +75,15 @@ module Projects
create_tmp_storage_dir
File.open(tmp_filename, 'wb') do |file|
begin
yield file
rescue StandardError => e
# If the lfs file is successfully downloaded it will be removed
# when it is added to the project's lfs files.
# Nevertheless if any excetion raises the file would remain
# in the file system. Here we ensure to remove it
File.unlink(file) if File.exist?(file)
raise e
end
yield file
rescue StandardError => e
# If the lfs file is successfully downloaded it will be removed
# when it is added to the project's lfs files.
# Nevertheless if any excetion raises the file would remain
# in the file system. Here we ensure to remove it
File.unlink(file) if File.exist?(file)
raise e
end
end
......
......@@ -2,7 +2,7 @@
class ShaValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
return if value.blank? || value.match(/\A\h{40}\z/)
return if value.blank? || Commit.valid_hash?(value)
record.errors.add(attribute, 'is not a valid SHA')
end
......
......@@ -38,4 +38,4 @@
%li= link_to _('New project'), new_project_path, class: 'qa-global-new-project-link'
- if current_user.can_create_group?
%li= link_to _('New group'), new_group_path
%li= link_to _('New snippet'), new_snippet_path
%li= link_to _('New snippet'), new_snippet_path, class: 'qa-global-new-snippet-link'
......@@ -29,7 +29,7 @@
- if dashboard_nav_link?(:snippets)
= nav_link(controller: 'dashboard/snippets', html_options: { class: ["d-none d-xl-block", ("d-lg-block" unless has_extra_nav_icons?)] }) do
= link_to dashboard_snippets_path, class: 'dashboard-shortcuts-snippets', title: _('Snippets') do
= link_to dashboard_snippets_path, class: 'dashboard-shortcuts-snippets qa-snippets-link', title: _('Snippets') do
= _('Snippets')
- if any_dashboard_nav_link?([:groups, :milestones, :activity, :snippets])
......
......@@ -20,13 +20,14 @@
= _('Overview')
%ul.sidebar-sub-level-items
= nav_link(path: ['groups#show', 'groups#activity', 'groups#subgroups'], html_options: { class: "fly-out-top-item" } ) do
= nav_link(path: ['groups#show', 'groups#details', 'groups#activity', 'groups#subgroups'], html_options: { class: "fly-out-top-item" } ) do
= link_to group_path(@group) do
%strong.fly-out-top-item-name
= _('Overview')
%li.divider.fly-out-top-item
= nav_link(path: ['groups#show', 'groups#subgroups'], html_options: { class: 'home' }) do
= link_to group_path(@group), title: _('Group details') do
= nav_link(path: ['groups#show', 'groups#details', 'groups#subgroups'], html_options: { class: 'home' }) do
= link_to details_group_path(@group), title: _('Group details') do
%span
= _('Details')
......@@ -40,9 +41,9 @@
- if group_sidebar_link?(:contribution_analytics)
= nav_link(path: 'analytics#show') do
= link_to group_analytics_path(@group), title: 'Contribution Analytics', data: {placement: 'right'} do
= link_to group_analytics_path(@group), title: _('Contribution Analytics'), data: { placement: 'right' } do
%span
Contribution Analytics
= _('Contribution Analytics')
= render_if_exists "layouts/nav/ee/epic_link", group: @group
......
......@@ -6,6 +6,7 @@
= render 'shared/no_ssh'
= render 'shared/no_password'
= render 'shared/shared_runners_minutes_limit', project: project
= render 'shared/auto_devops_implicitly_enabled_banner', project: project
- unless project.empty_repo?
= render 'shared/auto_devops_implicitly_enabled_banner', project: project
- if project.above_size_limit?
= render 'above_size_limit_warning'
......@@ -57,7 +57,10 @@
- if can?(current_user, :download_code, @project)
%nav.project-stats
.nav-links.quick-links
= render 'stat_anchor_list', anchors: @project.statistics_anchors(show_auto_devops_callout: show_auto_devops_callout)
- if @project.empty_repo?
= render 'stat_anchor_list', anchors: @project.empty_repo_statistics_anchors
- else
= render 'stat_anchor_list', anchors: @project.statistics_anchors(show_auto_devops_callout: show_auto_devops_callout)
.home-panel-home-desc.mt-1
- if @project.description.present?
......
.file-header-content
= blob_icon blob.mode, blob.name
%strong.file-title-name
%strong.file-title-name.qa-file-title-name
= blob.name
= copy_file_path_button(blob.path)
......
......@@ -7,89 +7,64 @@
%div{ class: [container_class, ("limit-container-width" unless fluid_layout)] }
= render "home_panel"
.project-empty-note-panel
%h4.append-bottom-20
= _('The repository for this project is empty')
%h4.prepend-top-0.append-bottom-8
= _('The repository for this project is empty')
- if @project.can_current_user_push_code?
%p
- link_to_cli = link_to _('command line instructions'), '#repo-command-line-instructions'
= _('If you already have files you can push them using the %{link_to_cli} below.').html_safe % { link_to_cli: link_to_cli }
%p
%em
- link_to_protected_branches = link_to _('Learn more about protected branches'), help_page_path('user/project/protected_branches')
= _('Note that the master branch is automatically protected. %{link_to_protected_branches}').html_safe % { link_to_protected_branches: link_to_protected_branches }
%hr
%p
- link_to_auto_devops_settings = link_to(s_('AutoDevOps|enable Auto DevOps'), project_settings_ci_cd_path(@project, anchor: 'autodevops-settings'))
- link_to_add_kubernetes_cluster = link_to(s_('AutoDevOps|add a Kubernetes cluster'), new_project_cluster_path(@project))
= s_('AutoDevOps|You can automatically build and test your application if you %{link_to_auto_devops_settings} for this project. You can automatically deploy it as well, if you %{link_to_add_kubernetes_cluster}.').html_safe % { link_to_auto_devops_settings: link_to_auto_devops_settings, link_to_add_kubernetes_cluster: link_to_add_kubernetes_cluster }
- if @project.can_current_user_push_code?
%p.append-bottom-0
= _('You can create files directly in GitLab using one of the following options.')
%hr
%p
= _('Otherwise it is recommended you start with one of the options below.')
.prepend-top-20
%nav.project-buttons
.scrolling-tabs-container.inner-page-scroll-tabs.is-smaller.qa-quick-actions
.fade-left= icon('angle-left')
.fade-right= icon('angle-right')
.nav-links.scrolling-tabs.quick-links
= render 'stat_anchor_list', anchors: @project.empty_repo_statistics_buttons
.project-buttons.qa-quick-actions
= render 'stat_anchor_list', anchors: @project.empty_repo_statistics_buttons
- if can?(current_user, :push_code, @project)
%div
.prepend-top-20
.empty_wrapper
%h3#repo-command-line-instructions.page-title-empty
= _('Command line instructions')
.git-empty.js-git-empty
%fieldset
%h5= _('Git global setup')
%pre.bg-light
:preserve
git config --global user.name "#{h git_user_name}"
git config --global user.email "#{h git_user_email}"
%fieldset
%h5= _('Create a new repository')
%pre.bg-light
:preserve
git clone #{ content_tag(:span, default_url_to_repo, class: 'js-clone')}
cd #{h @project.path}
touch README.md
git add README.md
git commit -m "add README"
- if @project.can_current_user_push_to_default_branch?
%span><
git push -u origin master
.empty-wrapper.prepend-top-32
%h3#repo-command-line-instructions.page-title-empty
= _('Command line instructions')
%p
= _('You can also upload existing files from your computer using the instructions below.')
.git-empty.js-git-empty
%fieldset
%h5= _('Git global setup')
%pre.bg-light
:preserve
git config --global user.name "#{h git_user_name}"
git config --global user.email "#{h git_user_email}"
%fieldset
%h5= _('Existing folder')
%pre.bg-light
:preserve
cd existing_folder
git init
git remote add origin #{ content_tag(:span, default_url_to_repo, class: 'js-clone')}
git add .
git commit -m "Initial commit"
- if @project.can_current_user_push_to_default_branch?
%span><
git push -u origin master
%fieldset
%h5= _('Create a new repository')
%pre.bg-light
:preserve
git clone #{ content_tag(:span, default_url_to_repo, class: 'js-clone')}
cd #{h @project.path}
touch README.md
git add README.md
git commit -m "add README"
- if @project.can_current_user_push_to_default_branch?
%span><
git push -u origin master
%fieldset
%h5= _('Existing Git repository')
%pre.bg-light
:preserve
cd existing_repo
git remote rename origin old-origin
git remote add origin #{ content_tag(:span, default_url_to_repo, class: 'js-clone')}
- if @project.can_current_user_push_to_default_branch?
%span><
git push -u origin --all
git push -u origin --tags
%fieldset
%h5= _('Push an existing folder')
%pre.bg-light
:preserve
cd existing_folder
git init
git remote add origin #{ content_tag(:span, default_url_to_repo, class: 'js-clone')}
git add .
git commit -m "Initial commit"
- if @project.can_current_user_push_to_default_branch?
%span><
git push -u origin master
- if can? current_user, :remove_project, @project
.prepend-top-20
= link_to _('Remove project'), [@project.namespace.becomes(Namespace), @project], data: { confirm: remove_project_message(@project)}, method: :delete, class: "btn btn-inverted btn-remove float-right"
%fieldset
%h5= _('Push an existing Git repository')
%pre.bg-light
:preserve
cd existing_repo
git remote rename origin old-origin
git remote add origin #{ content_tag(:span, default_url_to_repo, class: 'js-clone')}
- if @project.can_current_user_push_to_default_branch?
%span><
git push -u origin --all
git push -u origin --tags
......@@ -24,6 +24,6 @@
.input-group-append
= clipboard_button(target: '#project_clone', title: _("Copy URL to clipboard"), class: "input-group-text btn-default btn-clipboard")
= geo_button(modal_target: '#modal-geo-info')
= geo_button(modal_target: '#modal-geo-info') if Gitlab::Geo.secondary?
= render 'shared/geo_info_modal', project: project if Gitlab::Geo.secondary?
.file-content.code.js-syntax-highlight
.file-content.code.js-syntax-highlight.qa-file-content
.line-numbers
- if blob.data.present?
- link_icon = icon('link')
......
......@@ -9,7 +9,7 @@
.form-group.row
= f.label :title, class: 'col-form-label col-sm-2'
.col-sm-10
= f.text_field :title, class: 'form-control', required: true, autofocus: true
= f.text_field :title, class: 'form-control qa-snippet-title', required: true, autofocus: true
= render 'shared/form_elements/description', model: @snippet, project: @project, form: f
......@@ -21,7 +21,7 @@
.col-sm-10
.file-holder.snippet
.js-file-title.file-title
= f.text_field :file_name, placeholder: "Optionally name this file to add code highlighting, e.g. example.rb for Ruby.", class: 'form-control snippet-file-name'
= f.text_field :file_name, placeholder: "Optionally name this file to add code highlighting, e.g. example.rb for Ruby.", class: 'form-control snippet-file-name qa-snippet-file-name'
.file-content.code
%pre#editor= @snippet.content
= f.hidden_field :content, class: 'snippet-file-content'
......@@ -31,7 +31,7 @@
.form-actions
- if @snippet.new_record?
= f.submit 'Create snippet', class: "btn-success btn"
= f.submit 'Create snippet', class: "btn-success btn qa-create-snippet-button"
- else
= f.submit 'Save changes', class: "btn-success btn"
......
.detail-page-header
.detail-page-header-body
.snippet-box.has-tooltip.inline.append-right-5{ title: snippet_visibility_level_description(@snippet.visibility_level, @snippet), data: { container: "body" } }
.snippet-box.qa-snippet-box.has-tooltip.inline.append-right-5{ title: snippet_visibility_level_description(@snippet.visibility_level, @snippet), data: { container: "body" } }
%span.sr-only
= visibility_level_label(@snippet.visibility_level)
= visibility_level_icon(@snippet.visibility_level, fw: false)
......@@ -17,11 +17,11 @@
= render "snippets/actions"
.snippet-header.limited-header-width
%h2.snippet-title.prepend-top-0.append-bottom-0
%h2.snippet-title.prepend-top-0.append-bottom-0.qa-snippet-title
= markdown_field(@snippet, :title)
- if @snippet.description.present?
.description
.description.qa-snippet-description
.wiki
= markdown_field(@snippet, :description)
%textarea.hidden.js-task-list-field
......@@ -34,7 +34,7 @@
.embed-snippet
.input-group
.input-group-prepend
%button.btn.btn-svg.embed-toggle.input-group-text{ 'data-toggle': 'dropdown', type: 'button' }
%button.btn.btn-svg.embed-toggle.input-group-text.qa-embed-type{ 'data-toggle': 'dropdown', type: 'button' }
%span.js-embed-action= _("Embed")
= sprite_icon('angle-down', size: 12, css_class: 'caret-down')
%ul.dropdown-menu.dropdown-menu-selectable.embed-toggle-list
......
......@@ -25,11 +25,9 @@ module WaitableWorker
failed = []
args_list.each do |args|
begin
new.perform(*args)
rescue
failed << args
end
new.perform(*args)
rescue
failed << args
end
bulk_perform_async(failed) if failed.present?
......
......@@ -20,11 +20,9 @@ class CreateGpgSignatureWorker
# This calculates and caches the signature in the database
commits.each do |commit|
begin
Gitlab::Gpg::Commit.new(commit).signature
rescue => e
Rails.logger.error("Failed to create signature for commit #{commit.id}. Error: #{e.message}")
end
Gitlab::Gpg::Commit.new(commit).signature
rescue => e
Rails.logger.error("Failed to create signature for commit #{commit.id}. Error: #{e.message}")
end
end
# rubocop: enable CodeReuse/ActiveRecord
......
......@@ -52,24 +52,22 @@ class EmailsOnPushWorker
end
valid_recipients(recipients).each do |recipient|
begin
send_email(
recipient,
project_id,
author_id: author_id,
ref: ref,
action: action,
compare: compare,
reverse_compare: reverse_compare,
diff_refs: diff_refs,
send_from_committer_email: send_from_committer_email,
disable_diffs: disable_diffs
)
# These are input errors and won't be corrected even if Sidekiq retries
rescue Net::SMTPFatalError, Net::SMTPSyntaxError => e
logger.info("Failed to send e-mail for project '#{project.full_name}' to #{recipient}: #{e}")
end
send_email(
recipient,
project_id,
author_id: author_id,
ref: ref,
action: action,
compare: compare,
reverse_compare: reverse_compare,
diff_refs: diff_refs,
send_from_committer_email: send_from_committer_email,
disable_diffs: disable_diffs
)
# These are input errors and won't be corrected even if Sidekiq retries
rescue Net::SMTPFatalError, Net::SMTPSyntaxError => e
logger.info("Failed to send e-mail for project '#{project.full_name}' to #{recipient}: #{e}")
end
ensure
@email = nil
......
......@@ -126,11 +126,9 @@ module ObjectStorage
def process_uploader(uploader)
MigrationResult.new(uploader.upload).tap do |result|
begin
uploader.migrate!(@to_store)
rescue => e
result.error = e
end
uploader.migrate!(@to_store)
rescue => e
result.error = e
end
end
end
......
......@@ -8,16 +8,15 @@ class PipelineScheduleWorker
def perform
Ci::PipelineSchedule.active.where("next_run_at < ?", Time.now)
.preload(:owner, :project).find_each do |schedule|
begin
Ci::CreatePipelineService.new(schedule.project,
schedule.owner,
ref: schedule.ref)
.execute!(:schedule, ignore_skip_ci: true, save_on_errors: true, schedule: schedule)
rescue => e
error(schedule, e)
ensure
schedule.schedule_next_run!
end
Ci::CreatePipelineService.new(schedule.project,
schedule.owner,
ref: schedule.ref)
.execute!(:schedule, ignore_skip_ci: true, save_on_errors: true, schedule: schedule)
rescue => e
error(schedule, e)
ensure
schedule.schedule_next_run!
end
end
# rubocop: enable CodeReuse/ActiveRecord
......
......@@ -6,11 +6,9 @@ class RemoveExpiredMembersWorker
def perform
Member.expired.find_each do |member|
begin
Members::DestroyService.new.execute(member, skip_authorization: true)
rescue => ex
logger.error("Expired Member ID=#{member.id} cannot be removed - #{ex}")
end
Members::DestroyService.new.execute(member, skip_authorization: true)
rescue => ex
logger.error("Expired Member ID=#{member.id} cannot be removed - #{ex}")
end
end
end
---
title: 'Project: Improve empty repository state UI'
merge_request: 26024
author:
type: other
---
title: Explicitly set master_auth setting to enable basic auth and client certificate
for new GKE clusters
merge_request: 26018
author:
type: other
---
title: Fix bug in BitBucket imports with SHA shorter than 40 chars
merge_request: 26050
author:
type: fixed
......@@ -3,6 +3,6 @@ HealthCheck.setup do |config|
config.full_checks = %w(database migrations cache)
config.add_custom_check('geo') do
Gitlab::Geo::HealthCheck.perform_checks
Gitlab::Geo::HealthCheck.new.perform_checks
end
end
......@@ -14,10 +14,8 @@ module Rack
end
gitlab_trusted_proxies = Array(Gitlab.config.gitlab.trusted_proxies).map do |proxy|
begin
IPAddr.new(proxy)
rescue IPAddr::InvalidAddressError
end
IPAddr.new(proxy)
rescue IPAddr::InvalidAddressError
end.compact
Rails.application.config.action_dispatch.trusted_proxies = (
......
......@@ -119,6 +119,15 @@ module.exports = function(config) {
reporters: ['mocha'],
webpack: webpackConfig,
webpackMiddleware: { stats: 'errors-only' },
plugins: [
'karma-chrome-launcher',
'karma-coverage-istanbul-reporter',
'karma-jasmine',
'karma-junit-reporter',
'karma-mocha-reporter',
'karma-sourcemap-loader',
'karma-webpack',
],
};
if (process.env.CI) {
......@@ -127,6 +136,19 @@ module.exports = function(config) {
outputFile: 'junit_karma.xml',
useBrowserName: false,
};
} else {
// ignore 404s in local environment because we are not fixing them and they bloat the log
function ignore404() {
return (request, response /* next */) => {
response.writeHead(404);
return response.end('NOT FOUND');
};
}
karmaConfig.middleware = ['ignore-404'];
karmaConfig.plugins.push({
'middleware:ignore-404': ['factory', ignore404],
});
}
if (process.env.BABEL_ENV === 'coverage' || process.env.NODE_ENV === 'coverage') {
......
......@@ -14,6 +14,7 @@ constraints(::Constraints::GroupUrlConstrainer.new) do
get :issues, as: :issues_group
get :merge_requests, as: :merge_requests_group
get :projects, as: :projects_group
get :details, as: :details_group # needed for EE but left here to provide helpers for CE partials
get :activity, as: :activity_group
put :transfer, as: :transfer_group
# TODO: Remove as part of refactor in https://gitlab.com/gitlab-org/gitlab-ce/issues/49693
......
......@@ -324,6 +324,10 @@ module.exports = {
reportFilename: path.join(ROOT_PATH, 'webpack-report/index.html'),
statsFilename: path.join(ROOT_PATH, 'webpack-report/stats.json'),
}),
new webpack.DefinePlugin({
'process.env.EE': JSON.stringify(IS_EE),
}),
].filter(Boolean),
devServer: {
......
......@@ -126,11 +126,10 @@ class ProjectForeignKeysWithCascadingDeletes < ActiveRecord::Migration[4.2]
queues.each do |queue|
# Stealing is racy so it's possible a pop might be called on an
# already-empty queue.
begin
remove_orphans(*queue.pop(true))
stolen = true
rescue ThreadError
end
remove_orphans(*queue.pop(true))
stolen = true
rescue ThreadError
end
break unless stolen
......
# Container Scanning with GitLab CI/CD
CAUTION: **Caution:**
The job definition shown below is supported on GitLab 11.5 and later versions.
It also requires the GitLab Runner 11.5 or later.
For earlier versions, use the [previous job definitions](#previous-job-definitions).
# Container Scanning with GitLab CI/CD **[ULTIMATE]**
You can check your Docker images (or more precisely the containers) for known
vulnerabilities by using [Clair](https://github.com/coreos/clair) and
[clair-scanner](https://github.com/arminc/clair-scanner), two open source tools
for Vulnerability Static Analysis for containers.
First, you need GitLab Runner with
[docker-in-docker executor](../docker/using_docker_build.md#use-docker-in-docker-executor).
These examples show how to run Container Scanning on your Docker image by using GitLab CI/CD.
CAUTION: **Caution:**
Starting with GitLab 11.5, Container Scanning feature is licensed under the name `container_scanning`.
While the old name `sast_container` is still maintained, it has been deprecated with GitLab 11.5 and
may be removed in next major release, GitLab 12.0. You are advised to update your current `.gitlab-ci.yml`
configuration to reflect that change if you are using the `$GITLAB_FEATURES` environment variable.
## Prerequisites
To run a Container Scanning job, you need:
- a GitLab Runner with
[docker-in-docker executor](https://docs.gitlab.com/runner/executors/docker.html#use-docker-in-docker-with-privileged-mode).
- to [build and push](../../ci/docker/using_docker_build.md#container-registry-examples) your Docker image
using the [Container Registry](https://docs.gitlab.com/ee/user/project/container_registry.html) running within your GitLab installation.
## Configuring with templates
Since GitLab 11.9, a CI/CD template with the default Container Scanning job definition is provided as a part of your GitLab installation.
This section describes how to use it and customize its execution.
### Using job definition template
CAUTION: **Caution:**
The CI/CD template for job definition is supported on GitLab 11.9 and later versions.
For earlier versions, use the [manual job definition](#manual-job-definition).
Once you set up the Runner, add a new job to `.gitlab-ci.yml` using [the CI/CD template](../../ci/yaml/README.md#includetemplate) for Container Scanning:
```yaml
include:
template: Container-Scanning.gitlab-ci.yml
```
If you want to whitelist some specific vulnerabilities, you can do so by defining
them in a [YAML file](https://github.com/arminc/clair-scanner/blob/master/README.md#example-whitelist-yaml-file),
in our case its named `clair-whitelist.yml`.
### Scanning results
The above example will create a `container_scanning` job in your CI/CD pipeline, pull
the image from the [Container Registry](../../user/project/container_registry.md)
(whose name is defined from the two `CI_APPLICATION_` variables) and scan it
for possible vulnerabilities. The report will be saved as a
[Container Scanning report artifact](../yaml/README.md#artifactsreportscontainer_scanning-ultimate)
that you can later download and analyze.
Due to implementation limitations we always take the latest Container Scanning artifact available.
TIP: **Tip:**
For [GitLab Ultimate][ee] users, this information will
be automatically extracted and shown right in the merge request widget.
[Learn more on Container Scanning in merge requests](../../user/project/merge_requests/container_scanning.html).
Once you set up the Runner, add a new job to `.gitlab-ci.yml` that
generates the expected report:
## Manual job definition
CAUTION: **Caution:**
The job definition shown below is supported on GitLab 11.5 and later versions _(although it's preferred to use
[the job definition template](#using-job-definition-template) since 11.9)_.
It also requires the GitLab Runner 11.5 or later.
For earlier versions, use the [previous job definitions](#previous-job-definitions).
If you are using GitLab prior to 11.9, you can define it manually using the following snippet:
```yaml
container_scanning:
......@@ -47,29 +100,6 @@ container_scanning:
container_scanning: gl-container-scanning-report.json
```
The above example will create a `container_scanning` job in your CI/CD pipeline, pull
the image from the [Container Registry](../../user/project/container_registry.md)
(whose name is defined from the two `CI_APPLICATION_` variables) and scan it
for possible vulnerabilities. The report will be saved as a
[Container Scanning report artifact](../yaml/README.md#artifactsreportscontainer_scanning-ultimate)
that you can later download and analyze.
Due to implementation limitations we always take the latest Container Scanning artifact available.
If you want to whitelist some specific vulnerabilities, you can do so by defining
them in a [YAML file](https://github.com/arminc/clair-scanner/blob/master/README.md#example-whitelist-yaml-file),
in our case its named `clair-whitelist.yml`.
TIP: **Tip:**
For [GitLab Ultimate][ee] users, this information will
be automatically extracted and shown right in the merge request widget.
[Learn more on Container Scanning in merge requests](../../user/project/merge_requests/container_scanning.html).
CAUTION: **Caution:**
Starting with GitLab 11.5, Container Scanning feature is licensed under the name `container_scanning`.
While the old name `sast_container` is still maintained, it has been deprecated with GitLab 11.5 and
may be removed in next major release, GitLab 12.0. You are advised to update your current `.gitlab-ci.yml`
configuration to reflect that change if you are using the `$GITLAB_FEATURES` environment variable.
## Previous job definitions
CAUTION: **Caution:**
......@@ -111,7 +141,7 @@ container_scanning:
paths: [gl-container-scanning-report.json]
```
Alternatively the job name could be `sast:container`
Alternatively, the job name could be `sast:container`
and the artifact name could be `gl-sast-container-report.json`.
These names have been deprecated with GitLab 11.0
and may be removed in next major release, GitLab 12.0.
......
# Dynamic Application Security Testing with GitLab CI/CD
CAUTION: **Caution:**
The job definition shown below is supported on GitLab 11.5 and later versions.
It also requires the GitLab Runner 11.5 or later.
For earlier versions, use the [previous job definitions](#previous-job-definitions).
[Dynamic Application Security Testing (DAST)](https://en.wikipedia.org/wiki/Dynamic_program_analysis)
[Dynamic Application Security Testing (DAST)](https://en.wikipedia.org/wiki/Dynamic_Application_Security_Testing)
is using the popular open source tool [OWASP ZAProxy](https://github.com/zaproxy/zaproxy)
to perform an analysis on your running web application.
Since it is based on [ZAP Baseline](https://github.com/zaproxy/zaproxy/wiki/ZAP-Baseline-Scan)
......@@ -14,13 +9,114 @@ it will not actively attack your application.
It can be very useful combined with [Review Apps](../review_apps/index.md).
## Example
These examples show how to run DAST on your running web application by using GitLab CI/CD.
## Prerequisites
First, you need GitLab Runner with
To run a DAST job, you need GitLab Runner with
[docker executor](https://docs.gitlab.com/runner/executors/docker.html).
Once you set up the Runner, add a new job to `.gitlab-ci.yml` that
generates the expected report:
## Configuring with templates
Since GitLab 11.9, a CI/CD template with the default DAST job definition is provided as a part of your GitLab installation.
This section describes how to use it and customize its execution.
### Using job definition template
CAUTION: **Caution:**
The CI/CD template for job definition is supported on GitLab 11.9 and later versions.
For earlier versions, use the [manual job definition](#manual-job-definition).
Once you set up the Runner, add a new job to `.gitlab-ci.yml` using [the CI/CD template](../../ci/yaml/README.md#includetemplate) for DAST:
```yaml
include:
template: DAST.gitlab-ci.yml
```
The above example will create a `dast` job in your CI/CD pipeline which will run
the tests on the URL defined in the `DAST_WEBSITE` variable (change it to use your
own) and scan it for possible vulnerabilities.
It's also possible to authenticate the user before performing DAST checks:
```yaml
include:
template: DAST.gitlab-ci.yml
variables:
DAST_AUTH_URL: https://example.com/sign-in
DAST_USERNAME: john.doe@example.com
DAST_PASSWORD: john-doe-password
DAST_USERNAME_FIELD: session[user] # the name of username field at the sign-in HTML form
DAST_PASSWORD_FIELD: session[password] # the name of password field at the sign-in HTML form
```
### Scanning results
The report will be saved as a
[DAST report artifact](../yaml/README.md#artifactsreportsdast-ultimate)
that you can later download and analyze.
Due to implementation limitations we always take the latest DAST artifact available.
TIP: **Tip:**
For [GitLab Ultimate][ee] users, this information will
be automatically extracted and shown right in the merge request widget.
[Learn more on DAST in merge requests](../../user/project/merge_requests/dast.md).
### Customizing the template
You can customize DAST job execution in various ways of different granularity.
#### Scanning tool settings
DAST tool settings can be changed through environment variables. These variables are documented in the:
- Job definition [template](#using-job-definition-template).
- DAST [README](https://gitlab.com/gitlab-org/security-products/dast#settings).
The customization itself is performed by using the [`variables`](https://docs.gitlab.com/ee/ci/yaml/#variables)
parameter in the project's pipeline configuration file (`.gitlab-ci.yml`):
```yaml
include:
template: DAST.gitlab-ci.yml
variables:
DAST_TARGET_AVAILABILITY_TIMEOUT: 120
```
Because template is evaluated [before](../yaml/README.md#include) the pipeline configuration,
the last mention of the variable will take precedence.
#### Overriding job definition
If you want to override the job definition (for example, change properties like `variables` or `dependencies`), you need to declare
its definition after the template inclusion and specify any additional keys under it. For example:
```yaml
include:
template: DAST.gitlab-ci.yml
dast:
stage: dast # IMPORTANT: don't forget to add this
variables:
CI_DEBUG_TRACE: "true"
```
CAUTION: **Caution:**
As DAST job belongs to a separate `"dast"` stage that runs after all [default stages](../yaml/README.md#stages),
don't forget to add `stage: dast` entry when you override the template job definition.
## Manual job definition
CAUTION: **Caution:**
The job definition shown below is supported on GitLab 11.5 and later versions _(although it's preferred to use
[the job definition template](#using-job-definition-template) since 11.9)_.
It also requires the GitLab Runner 11.5 or later.
For earlier versions, use the [previous job definitions](#previous-job-definitions).
If you are using GitLab prior to 11.9, you can define it manually using the following snippet:
```yaml
dast:
......@@ -37,14 +133,9 @@ dast:
dast: gl-dast-report.json
```
The above example will create a `dast` job in your CI/CD pipeline which will run
the tests on the URL defined in the `website` variable (change it to use your
own) and scan it for possible vulnerabilities. The report will be saved as a
[DAST report artifact](../yaml/README.md#artifactsreportsdast-ultimate)
that you can later download and analyze.
Due to implementation limitations we always take the latest DAST artifact available.
where the `website` variable is supposed to hold the URL to run the tests against.
It's also possible to authenticate the user before performing DAST checks:
For an authenticated scan, use the following definition:
```yaml
dast:
......@@ -66,14 +157,10 @@ dast:
reports:
dast: gl-dast-report.json
```
See [zaproxy documentation](https://gitlab.com/gitlab-org/security-products/zaproxy)
to learn more about authentication settings.
TIP: **Tip:**
For [GitLab Ultimate][ee] users, this information will
be automatically extracted and shown right in the merge request widget.
[Learn more on DAST in merge requests](../../user/project/merge_requests/dast.md).
## Previous job definitions
CAUTION: **Caution:**
......@@ -97,6 +184,6 @@ dast:
- cp /zap/wrk/gl-dast-report.json .
artifacts:
paths: [gl-dast-report.json]
```
```
[ee]: https://about.gitlab.com/pricing/
# Dependency Scanning with GitLab CI/CD **[ULTIMATE]**
CAUTION: **Caution:**
The job definition shown below is supported on GitLab 11.5 and later versions.
It also requires the GitLab Runner 11.5 or later.
For earlier versions, use the [previous job definitions](#previous-job-definitions).
These examples show how to run Dependency Scanning on your project's dependencies by using GitLab CI/CD.
## Prerequisites
This example shows how to run Dependency Scanning on your
project's dependencies by using GitLab CI/CD.
To run a Dependency Scanning job, you need GitLab Runner with
[docker-in-docker executor](https://docs.gitlab.com/runner/executors/docker.html#use-docker-in-docker-with-privileged-mode).
## Configuring with templates
First, you need GitLab Runner with
[docker-in-docker executor](../docker/using_docker_build.md#use-docker-in-docker-executor).
Since GitLab 11.9, a CI/CD template with the default Dependency Scanning job definition is provided as a part of your GitLab installation.
This section describes how to use it and customize its execution.
Once you set up the Runner, add a new job to `.gitlab-ci.yml` that
generates the expected report:
### Using job definition template
CAUTION: **Caution:**
The CI/CD template for job definition is supported on GitLab 11.9 and later versions.
For earlier versions, use the [manual job definition](#manual-job-definition).
Once you set up the Runner, add a new job to `.gitlab-ci.yml` using [the CI/CD template](../../ci/yaml/README.md#includetemplate) for Dependency Scanning:
```yaml
dependency_scanning:
image: docker:stable
variables:
DOCKER_DRIVER: overlay2
allow_failure: true
services:
- docker:stable-dind
script:
- export SP_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/')
- docker run
--env DEP_SCAN_DISABLE_REMOTE_CHECKS="${DEP_SCAN_DISABLE_REMOTE_CHECKS:-false}"
--volume "$PWD:/code"
--volume /var/run/docker.sock:/var/run/docker.sock
"registry.gitlab.com/gitlab-org/security-products/dependency-scanning:$SP_VERSION" /code
artifacts:
reports:
dependency_scanning: gl-dependency-scanning-report.json
include:
template: Dependency-Scanning.gitlab-ci.yml
```
### Scanning results
The above example will create a `dependency_scanning` job in your CI/CD pipeline
and scan your dependencies for possible vulnerabilities. The report will be saved as a
[Dependency Scanning report artifact](../../ci/yaml/README.md#artifactsreportsdependency_scanning-ultimate)
......@@ -54,16 +46,94 @@ is used to detect the languages/package managers and in turn runs the matching s
Some security scanners require to send a list of project dependencies to GitLab
central servers to check for vulnerabilities. To learn more about this or to
disable it, check the [GitLab Dependency Scanning documentation](https://gitlab.com/gitlab-org/security-products/dependency-scanning#remote-checks).
disable it, check the [GitLab Dependency Scanning documentation](https://gitlab.com/gitlab-org/security-products/dependency-scanning#remote-checks)
and the [customization guide](#job-execution-customization).
TIP: **Tip:**
For [GitLab Ultimate][ee] users, this information will
be automatically extracted and shown right in the merge request widget.
[Learn more on Dependency Scanning in merge requests](../../user/project/merge_requests/dependency_scanning.md).
## Supported languages and package managers
### Customizing the template
See [the full list of supported languages and package managers](../../user/project/merge_requests/dependency_scanning.md#supported-languages-and-dependency-managers).
You can customize Dependency Scanning job execution in various ways of different granularity.
#### Scanning tool settings
Dependency Scanning tool settings can be changed through environment variables. These variables are documented in the:
- Job definition [template](#using-job-definition-template).
- Dependency Scanning [README](https://gitlab.com/gitlab-org/security-products/dependency-scanning#settings).
The customization itself is performed by using the [`variables`](https://docs.gitlab.com/ee/ci/yaml/#variables)
parameter in the project's pipeline configuration file (`.gitlab-ci.yml`):
```yaml
include:
template: Dependency-Scanning.gitlab-ci.yml
variables:
DEP_SCAN_DISABLE_REMOTE_CHECKS: true
```
Because template is evaluated [before](../yaml/README.md#include) the pipeline configuration,
the last mention of the variable will take precedence.
#### Overriding job definition
If you want to override the job definition (for example, change properties like `variables` or `dependencies`), you need to declare
its definition after the template inclusion and specify any additional keys under it. For example:
```yaml
include:
template: Dependency-Scanning.gitlab-ci.yml
dependency_scanning:
variables:
CI_DEBUG_TRACE: "true"
```
## Manual job definition
CAUTION: **Caution:**
The job definition shown below is supported on GitLab 11.5 and later versions _(although it's preferred to use
[the job definition template](#using-job-definition-template) since 11.9)_.
It also requires the GitLab Runner 11.5 or later.
For earlier versions, use the [previous job definitions](#previous-job-definitions).
If you are using GitLab prior to 11.9, you can define it manually using the following snippet:
```yaml
dependency_scanning:
image: docker:stable
variables:
DOCKER_DRIVER: overlay2
allow_failure: true
services:
- docker:stable-dind
script:
- export DS_VERSION=${SP_VERSION:-$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/')}
- |
docker run \
--env DS_ANALYZER_IMAGES \
--env DS_ANALYZER_IMAGE_PREFIX \
--env DS_ANALYZER_IMAGE_TAG \
--env DS_DEFAULT_ANALYZERS \
--env DEP_SCAN_DISABLE_REMOTE_CHECKS \
--env DS_DOCKER_CLIENT_NEGOTIATION_TIMEOUT \
--env DS_PULL_ANALYZER_IMAGE_TIMEOUT \
--env DS_RUN_ANALYZER_TIMEOUT \
--volume "$PWD:/code" \
--volume /var/run/docker.sock:/var/run/docker.sock \
"registry.gitlab.com/gitlab-org/security-products/dependency-scanning:$DS_VERSION" /code
dependencies: []
artifacts:
reports:
dependency_scanning: gl-dependency-scanning-report.json
```
You can supply many other [settings variables](https://gitlab.com/gitlab-org/security-products/dependency-scanning#settings)
via `docker run --env` to customize your job execution.
## Previous job definitions
......@@ -85,14 +155,26 @@ dependency_scanning:
services:
- docker:stable-dind
script:
- export SP_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/')
- docker run
--env DEP_SCAN_DISABLE_REMOTE_CHECKS="${DEP_SCAN_DISABLE_REMOTE_CHECKS:-false}"
--volume "$PWD:/code"
--volume /var/run/docker.sock:/var/run/docker.sock
"registry.gitlab.com/gitlab-org/security-products/dependency-scanning:$SP_VERSION" /code
- export DS_VERSION=${SP_VERSION:-$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/')}
- |
docker run \
--env DS_ANALYZER_IMAGES \
--env DS_ANALYZER_IMAGE_PREFIX \
--env DS_ANALYZER_IMAGE_TAG \
--env DS_DEFAULT_ANALYZERS \
--env DEP_SCAN_DISABLE_REMOTE_CHECKS \
--env DS_DOCKER_CLIENT_NEGOTIATION_TIMEOUT \
--env DS_PULL_ANALYZER_IMAGE_TIMEOUT \
--env DS_RUN_ANALYZER_TIMEOUT \
--volume "$PWD:/code" \
--volume /var/run/docker.sock:/var/run/docker.sock \
"registry.gitlab.com/gitlab-org/security-products/dependency-scanning:$DS_VERSION" /code
artifacts:
paths: [gl-dependency-scanning-report.json]
```
## Supported languages and package managers
See [the full list of supported languages and package managers](../../user/project/merge_requests/dependency_scanning.md#supported-languages-and-dependency-managers).
[ee]: https://about.gitlab.com/pricing/
......@@ -269,7 +269,7 @@ The `releases` directory will hold all our deployments:
echo 'Cloning repository'
[ -d {{ $releases_dir }} ] || mkdir {{ $releases_dir }}
git clone --depth 1 {{ $repository }} {{ $new_release_dir }}
cd {{ $releases_dir }}
cd {{ $new_release_dir }}
git reset --hard {{ $commit }}
@endtask
......@@ -347,7 +347,7 @@ At the end, our `Envoy.blade.php` file will look like this:
echo 'Cloning repository'
[ -d {{ $releases_dir }} ] || mkdir {{ $releases_dir }}
git clone --depth 1 {{ $repository }} {{ $new_release_dir }}
cd {{ $releases_dir }}
cd {{ $new_release_dir }}
git reset --hard {{ $commit }}
@endtask
......
# Dependencies license management with GitLab CI/CD **[ULTIMATE]**
CAUTION: **Caution:**
The job definition shown below is supported on GitLab 11.5 and later versions.
It also requires the GitLab Runner 11.5 or later.
For earlier versions, use the [previous job definitions](#previous-job-definitions).
These examples show how to run License Management scanning on your project's dependencies by using GitLab CI/CD.
## Prerequisites
To run a License Management scanning job, you need GitLab Runner with
[docker executor](https://docs.gitlab.com/runner/executors/docker.html).
This example shows how to run the License Management tool on your
project's dependencies by using GitLab CI/CD.
## Configuring with templates
First, you need GitLab Runner with
[docker-in-docker executor](../docker/using_docker_build.md#use-docker-in-docker-executor).
Since GitLab 11.9, a CI/CD template with the default License Management scanning job definition is provided as a part of your GitLab installation.
This section describes how to use it and customize its execution.
Once you set up the Runner, add a new job to `.gitlab-ci.yml` that
generates the expected report:
### Using job definition template
CAUTION: **Caution:**
The CI/CD template for job definition is supported on GitLab 11.9 and later versions.
For earlier versions, use the [manual job definition](#manual-job-definition).
Once you set up the Runner, add a new job to `.gitlab-ci.yml` using [the CI/CD template](../../ci/yaml/README.md#includetemplate) for License Management:
```yaml
license_management:
image:
name: "registry.gitlab.com/gitlab-org/security-products/license-management:$CI_SERVER_VERSION_MAJOR-$CI_SERVER_VERSION_MINOR-stable"
entrypoint: [""]
stage: test
allow_failure: true
script:
- /run.sh analyze .
artifacts:
reports:
license_management: gl-license-management-report.json
include:
template: License-Management.gitlab-ci.yml
```
### Scanning results
The above example will create a `license_management` job in your CI/CD pipeline
and scan your dependencies to find their licenses. The report will be saved as a
[License Management report artifact](../../ci/yaml/README.md#artifactsreportslicense_management-ultimate)
that you can later download and analyze.
Due to implementation limitations we always take the latest License Management artifact available.
## Install custom project dependencies
TIP: **Tip:**
For [GitLab Ultimate][ee] users, this information will
be automatically extracted and shown right in the merge request widget.
[Learn more on License Management in merge requests](../../user/project/merge_requests/license_management.md).
### Customizing the template
#### Install custom project dependencies
> Introduced in GitLab Ultimate 11.4.
......@@ -50,14 +56,45 @@ of your application (ex: for a project with a `Gemfile`, the setup step will be
Example:
```yaml
include:
template: License-Management.gitlab-ci.yml
variables:
LICENSE_MANAGEMENT_SETUP_CMD: ./my-custom-install-script.sh
```
In this example, `my-custom-install-script.sh` is a shell script at the root of the project.
#### Overriding job definition
If you want to override the job definition (for example, change properties like `variables` or `dependencies`), you need to declare
its definition after the template inclusion and specify any additional keys under it. For example:
```yaml
include:
template: License-Management.gitlab-ci.yml
license_management:
stage: my-custom-stage
```
## Manual job definition
CAUTION: **Caution:**
The job definition shown below is supported on GitLab 11.5 and later versions _(although it's preferred to use
[the job definition template](#using-job-definition-template) since 11.9)_.
It also requires the GitLab Runner 11.5 or later.
For earlier versions, use the [previous job definitions](#previous-job-definitions).
If you are using GitLab prior to 11.9, you can define it manually using the following snippet:
```yaml
license_management:
image:
name: "registry.gitlab.com/gitlab-org/security-products/license-management:$CI_SERVER_VERSION_MAJOR-$CI_SERVER_VERSION_MINOR-stable"
entrypoint: [""]
stage: test
variables:
SETUP_CMD: ./my-custom-install-script.sh
allow_failure: true
script:
- /run.sh analyze .
......@@ -66,12 +103,23 @@ license_management:
license_management: gl-license-management-report.json
```
In this example, `my-custom-install-script.sh` is a shell script at the root of the project.
Install custom project dependencies via `SETUP_CMD` variable:
TIP: **Tip:**
For [GitLab Ultimate][ee] users, this information will
be automatically extracted and shown right in the merge request widget.
[Learn more on License Management in merge requests](../../user/project/merge_requests/license_management.md).
```yaml
license_management:
image:
name: "registry.gitlab.com/gitlab-org/security-products/license-management:$CI_SERVER_VERSION_MAJOR-$CI_SERVER_VERSION_MINOR-stable"
entrypoint: [""]
stage: test
variables:
SETUP_CMD: ./my-custom-install-script.sh
allow_failure: true
script:
- /run.sh analyze .
artifacts:
reports:
license_management: gl-license-management-report.json
```
## Previous job definitions
......
# Static Application Security Testing with GitLab CI/CD **[ULTIMATE]**
CAUTION: **Caution:**
The job definition shown below is supported on GitLab 11.5 and later versions.
It also requires the GitLab Runner 11.5 or later.
For earlier versions, use the [previous job definitions](#previous-job-definitions).
This example shows how to run
[Static Application Security Testing (SAST)](https://en.wikipedia.org/wiki/Static_program_analysis)
These examples show how to run [Static Application Security Testing (SAST)](https://en.wikipedia.org/wiki/Static_program_analysis)
on your project's source code by using GitLab CI/CD.
First, you need GitLab Runner with
[docker-in-docker executor](../docker/using_docker_build.md#use-docker-in-docker-executor).
## Prerequisites
To run a SAST job, you need GitLab Runner with
[docker-in-docker executor](https://docs.gitlab.com/runner/executors/docker.html#use-docker-in-docker-with-privileged-mode).
## Configuring with templates
Since GitLab 11.9, a CI/CD template with the default SAST job definition is provided as a part of your GitLab installation.
This section describes how to use it and customize its execution.
### Using job definition template
Once you set up the Runner, add a new job to `.gitlab-ci.yml` that
generates the expected report:
CAUTION: **Caution:**
The CI/CD template for job definition is supported on GitLab 11.9 and later versions.
For earlier versions, use the [manual job definition](#manual-job-definition).
Once you set up the Runner, add a new job to `.gitlab-ci.yml` using [the CI/CD template](../../ci/yaml/README.md#includetemplate) for SAST:
```yaml
sast:
image: docker:stable
variables:
DOCKER_DRIVER: overlay2
allow_failure: true
services:
- docker:stable-dind
script:
- export SP_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/')
- docker run
--env SAST_CONFIDENCE_LEVEL="${SAST_CONFIDENCE_LEVEL:-3}"
--volume "$PWD:/code"
--volume /var/run/docker.sock:/var/run/docker.sock
"registry.gitlab.com/gitlab-org/security-products/sast:$SP_VERSION" /app/bin/run /code
artifacts:
reports:
sast: gl-sast-report.json
include:
template: SAST.gitlab-ci.yml
```
### Scanning results
The above example will create a `sast` job in your CI/CD pipeline
and scan your dependencies for possible vulnerabilities. The report will be saved as a
and scan your project's source code for possible vulnerabilities. The report will be saved as a
[SAST report artifact](../../ci/yaml/README.md#artifactsreportssast-ultimate)
that you can later download and analyze.
Due to implementation limitations we always take the latest SAST artifact available.
......@@ -58,9 +51,89 @@ For [GitLab Ultimate][ee] users, this information will
be automatically extracted and shown right in the merge request widget.
[Learn more on SAST in merge requests](../../user/project/merge_requests/sast.md).
## Supported languages and frameworks
### Customizing the template
You can customize SAST job execution in various ways of different granularity.
#### Scanning tool settings
SAST tool settings can be changed through environment variables. These variables are documented in the:
- Job definition [template](#using-job-definition-template).
- SAST [README](https://gitlab.com/gitlab-org/security-products/sast#settings).
The customization itself is performed by using the [`variables`](https://docs.gitlab.com/ee/ci/yaml/#variables)
parameter in the project's pipeline configuration file (`.gitlab-ci.yml`):
```yaml
include:
template: SAST.gitlab-ci.yml
variables:
SAST_GOSEC_LEVEL: 2
```
Because template is evaluated [before](../yaml/README.md#include) the pipeline configuration,
the last mention of the variable will take precedence.
#### Overriding job definition
If you want to override the job definition (for example, change properties like `variables` or `dependencies`), you need to declare
its definition after the template inclusion and specify any additional keys under it. For example:
```yaml
include:
template: SAST.gitlab-ci.yml
sast:
variables:
CI_DEBUG_TRACE: "true"
```
## Manual job definition
CAUTION: **Caution:**
The job definition shown below is supported on GitLab 11.5 and later versions _(although it's preferred to use
[the job definition template](#using-job-definition-template) since 11.9)_.
It also requires the GitLab Runner 11.5 or later.
For earlier versions, use the [previous job definitions](#previous-job-definitions).
If you are using GitLab prior to 11.9, you can define it manually using the following snippet:
```yaml
sast:
stage: test
image: docker:stable
variables:
DOCKER_DRIVER: overlay2
allow_failure: true
services:
- docker:stable-dind
script:
- export SAST_VERSION=${SP_VERSION:-$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/')}
- |
docker run \
--env SAST_ANALYZER_IMAGES \
--env SAST_ANALYZER_IMAGE_PREFIX \
--env SAST_ANALYZER_IMAGE_TAG \
--env SAST_DEFAULT_ANALYZERS \
--env SAST_BRAKEMAN_LEVEL \
--env SAST_GOSEC_LEVEL \
--env SAST_FLAWFINDER_LEVEL \
--env SAST_DOCKER_CLIENT_NEGOTIATION_TIMEOUT \
--env SAST_PULL_ANALYZER_IMAGE_TIMEOUT \
--env SAST_RUN_ANALYZER_TIMEOUT \
--volume "$PWD:/code" \
--volume /var/run/docker.sock:/var/run/docker.sock \
"registry.gitlab.com/gitlab-org/security-products/sast:$SAST_VERSION" /app/bin/run /code
dependencies: []
artifacts:
reports:
sast: gl-sast-report.json
```
See [the full list of supported languages and frameworks](../../user/project/merge_requests/sast.md#supported-languages-and-frameworks).
You can supply many other [settings variables](https://gitlab.com/gitlab-org/security-products/sast#settings)
via `docker run --env` to customize your job execution.
## Previous job definitions
......@@ -82,12 +155,12 @@ sast:
services:
- docker:stable-dind
script:
- export SP_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/')
- export SAST_VERSION=${SP_VERSION:-$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/')}
- docker run
--env SAST_CONFIDENCE_LEVEL="${SAST_CONFIDENCE_LEVEL:-3}"
--volume "$PWD:/code"
--volume /var/run/docker.sock:/var/run/docker.sock
"registry.gitlab.com/gitlab-org/security-products/sast:$SP_VERSION" /app/bin/run /code
"registry.gitlab.com/gitlab-org/security-products/sast:$SAST_VERSION" /app/bin/run /code
artifacts:
paths: [gl-sast-report.json]
```
......
......@@ -2561,4 +2561,4 @@ git push -o ci.skip
[environment]: ../environments.md "CI/CD environments"
[schedules]: ../../user/project/pipelines/schedules.md "Pipelines schedules"
[variables]: ../variables/README.md "CI/CD variables"
[push-option]: https://git-scm.com/docs/git-push#git-push--oltoptiongt
[push-option]: https://git-scm.com/docs/git-push#Documentation/git-push.txt--oltoptiongt
......@@ -52,9 +52,12 @@ for audiences of all ages.
If a contributor is no longer actively working on a submitted merge request
we can decide that the merge request will be finished by one of our
[Merge request coaches][team] or close the merge request. We make this decision
based on how important the change is for our product vision. If a Merge request
based on how important the change is for our product vision. If a merge request
coach is going to finish the merge request we assign the
~"coach will finish" label.
~"coach will finish" label. When a team member picks up a community contribution,
we credit the original author by adding a changelog entry crediting the author
and optionally include the original author on at least one of the commits
within the MR.
## Helping others
......@@ -119,6 +122,7 @@ This [documentation](merge_request_workflow.md) outlines the current merge reque
- [Merge request guidelines](merge_request_workflow.md#merge-request-guidelines)
- [Contribution acceptance criteria](merge_request_workflow.md#contribution-acceptance-criteria)
- [Definition of done](merge_request_workflow.md#definition-of-done)
- [Dependencies](merge_request_workflow.md#dependencies)
## Style guides
......
......@@ -80,11 +80,10 @@ yield a useful result, and ensuring content is helpful and easy to consume.
## Text
- Split up long lines (wrap text), this makes it much easier to review and edit. Only
double line breaks are shown as a full line break by creating new paragraphs.
80-100 characters is the recommended line length.
- Splitting long lines (preferably up to 100 characters) can make it easier to provide feedback on small chunks of text.
- Insert an empty line for new paragraphs.
- Use sentence case for titles, headings, labels, menu items, and buttons.
- Jump a line between different markups (e.g., after every paragraph, header, list, etc). Example:
- Insert an empty line between different markups (e.g., after every paragraph, header, list, etc). Example:
```md
## Header
......
......@@ -15,7 +15,7 @@ information on general testing practices at GitLab.
## Jest
GitLab has started to migrate tests to the (Jest)[https://jestjs.io]
GitLab has started to migrate tests to the [Jest](https://jestjs.io)
testing framework. You can read a [detailed evaluation](https://gitlab.com/gitlab-org/gitlab-ce/issues/49171)
of Jest compared to our use of Karma and Jasmine. In summary, it will allow us
to improve the performance and consistency of our frontend tests.
......
......@@ -704,6 +704,7 @@ also be customized, and you can easily use a [custom buildpack](#custom-buildpac
| `INCREMENTAL_ROLLOUT_MODE`| From GitLab 11.4, this variable, if present, can be used to enable an [incremental rollout](#incremental-rollout-to-production-premium) of your application for the production environment.<br/>Set to: <ul><li>`manual`, for manual deployment jobs.</li><li>`timed`, for automatic rollout deployments with a 5 minute delay each one.</li></ul> |
| `TEST_DISABLED` | From GitLab 11.0, this variable can be used to disable the `test` job. If the variable is present, the job will not be created. |
| `CODE_QUALITY_DISABLED` | From GitLab 11.0, this variable can be used to disable the `codequality` job. If the variable is present, the job will not be created. |
| `LICENSE_MANAGEMENT_DISABLED` | From GitLab 11.0, this variable can be used to disable the `license_management` job. If the variable is present, the job will not be created. |
| `SAST_DISABLED` | From GitLab 11.0, this variable can be used to disable the `sast` job. If the variable is present, the job will not be created. |
| `DEPENDENCY_SCANNING_DISABLED` | From GitLab 11.0, this variable can be used to disable the `dependency_scanning` job. If the variable is present, the job will not be created. |
| `CONTAINER_SCANNING_DISABLED` | From GitLab 11.0, this variable can be used to disable the `sast:container` job. If the variable is present, the job will not be created. |
......
......@@ -30,7 +30,9 @@ each one separately.
## Supported features
The group security dashboard supports [SAST](../../project/merge_requests/sast.md), and [Dependency Scanning](../../project/merge_requests/dependency_scanning.md) reports.
The group security dashboard supports [SAST](../../project/merge_requests/sast.md),
[Dependency Scanning](../../project/merge_requests/dependency_scanning.md),
and [Container Scanning](../../project/merge_requests/container_scanning.md).
## Requirements
......
......@@ -63,6 +63,12 @@ are available:
- `%{commit_sha}`: ID of the most recent commit to the default branch of a
project's repository
NOTE: **NOTE**
Placeholders allow badges to expose otherwise-private information, such as the
default branch or commit SHA when the project is configured to have a private
repository. This is by design, as badges are intended to be used publicly. Avoid
using these placeholders if the information is sensitive.
## API
You can also configure badges via the GitLab API. As in the settings, there is
......
......@@ -75,6 +75,14 @@ new Kubernetes cluster to your project:
After a couple of minutes, your cluster will be ready to go. You can now proceed
to install some [pre-defined applications](#installing-applications).
NOTE: **Note:**
GitLab requires basic authentication enabled and a client certificate issued for
the cluster in order to setup an [initial service
account](#access-controls). Starting from [GitLab
11.10](https://gitlab.com/gitlab-org/gitlab-ce/issues/58208), the cluster
creation process will explicitly request that basic authentication and
client certificate is enabled.
## Adding an existing Kubernetes cluster
To add an existing Kubernetes cluster to your project:
......
......@@ -293,6 +293,8 @@ Approvers are suggested for merge requests based on the previous authors of the
## Filtering merge requests by approvers
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/9468) in [GitLab Starter](https://about.gitlab.com/pricing/) 11.9.
To filter merge requests by an individual approver, you can type (or select from
the dropdown) `approver` and select the user.
......
......@@ -35,7 +35,6 @@ The following languages and frameworks are supported.
| Language / framework | Scan tool |
|-------------------------|----------------------------------------------------------------------------------------|
| .NET | [Security Code Scan](https://security-code-scan.github.io) |
| Any | [Gitleaks](https://github.com/zricethezav/gitleaks), [TruffleHog](https://github.com/dxa4481/truffleHog) and [Diffence](https://github.com/techjacker/diffence) (secret detectors) |
| C/C++ | [Flawfinder](https://www.dwheeler.com/flawfinder/) |
| Go | [Gosec](https://github.com/securego/gosec) |
| Groovy (Ant, Gradle, Maven and SBT) | [find-sec-bugs](https://find-sec-bugs.github.io/) |
......@@ -48,6 +47,17 @@ The following languages and frameworks are supported.
| Scala (Ant, Gradle, Maven and SBT) | [find-sec-bugs](https://find-sec-bugs.github.io/) |
| Typescript | [TSLint Config Security](https://github.com/webschik/tslint-config-security/) |
## Secret Detection
GitLab is also able to detect secrets and credentials that have been unintentionally pushed to the repository.
For example, an API key that allows write access to third-party deployment environments.
This check is performed by a specific analyzer during the `sast` job. It runs regardless of the programming
language of your app, and you don't need to change anything to your
CI/CD configuration file to turn it on. Results are available in the SAST report.
GitLab currently includes [Gitleaks](https://github.com/zricethezav/gitleaks), [TruffleHog](https://github.com/dxa4481/truffleHog), and [Diffence](https://github.com/techjacker/diffence).
## How it works
First of all, you need to define a job in your `.gitlab-ci.yml` file that generates the
......
......@@ -109,7 +109,7 @@ all matching branches:
## Creating a protected branch
> [Introduced][https://gitlab.com/gitlab-org/gitlab-ce/issues/53361] in GitLab 11.9.
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/53361) in GitLab 11.9.
When a protected branch or wildcard protected branches are set to
[**No one** is **Allowed to push**](#using-the-allowed-to-merge-and-allowed-to-push-settings),
......
......@@ -12,4 +12,15 @@ export default {
helpCanaryDeploymentsPath: data.environmentsDataHelpCanaryDeploymentsPath,
};
},
computed: {
canaryCalloutProps() {
return {
canaryDeploymentFeatureId: this.canaryDeploymentFeatureId,
showCanaryDeploymentCallout: this.showCanaryDeploymentCallout,
userCalloutsPath: this.userCalloutsPath,
lockPromotionSvgPath: this.lockPromotionSvgPath,
helpCanaryDeploymentsPath: this.helpCanaryDeploymentsPath,
};
},
},
};
export default {
props: {
canaryDeploymentFeatureId: {
type: String,
required: true,
},
showCanaryDeploymentCallout: {
type: Boolean,
required: true,
},
userCalloutsPath: {
type: String,
required: true,
},
lockPromotionSvgPath: {
type: String,
required: true,
},
helpCanaryDeploymentsPath: {
type: String,
required: true,
},
},
};
import CeEnvironmentsStore from '~/environments/stores/environments_store';
export default class EnvironmentsStore extends CeEnvironmentsStore {
storeEnvironments(environments = []) {
super.storeEnvironments(environments);
/**
* Add the canary callout banner underneath the second environment listed.
*
* If there is only one environment, then add to it underneath the first.
*/
if (this.state.environments.length >= 2) {
this.state.environments[1].showCanaryCallout = true;
} else if (this.state.environments.length === 1) {
this.state.environments[0].showCanaryCallout = true;
}
}
/**
* Toggles deploy board visibility for the provided environment ID.
*
* @param {Object} environment
* @return {Array}
*/
toggleDeployBoard(environmentID) {
const environments = this.state.environments.slice();
this.state.environments = environments.map(env => {
let updated = Object.assign({}, env);
if (env.id === environmentID) {
updated = Object.assign({}, updated, {
isDeployBoardVisible: !env.isDeployBoardVisible,
});
}
return updated;
});
return this.state.environments;
}
}
import { CLUSTER_TYPE } from '~/clusters/constants';
/**
* Deploy boards are EE only.
*
* @param {Object} environment
* @returns {Object}
*/
// eslint-disable-next-line import/prefer-default-export
export const setDeployBoard = (oldEnvironmentState, environment) => {
let parsedEnvironment = environment;
if (
environment.size === 1 &&
environment.rollout_status &&
environment.cluster_type !== CLUSTER_TYPE.GROUP
) {
parsedEnvironment = Object.assign({}, environment, {
hasDeployBoard: true,
isDeployBoardVisible:
oldEnvironmentState.isDeployBoardVisible === false
? oldEnvironmentState.isDeployBoardVisible
: true,
deployBoardData:
environment.rollout_status.status === 'found' ? environment.rollout_status : {},
isLoadingDeployBoard: environment.rollout_status.status === 'loading',
isEmptyDeployBoard: environment.rollout_status.status === 'not_found',
});
}
return parsedEnvironment;
};
import initGroupDetails from '~/pages/groups/shared/group_details';
import initSecurityDashboard from 'ee/security_dashboard/index';
document.addEventListener('DOMContentLoaded', () => {
if (document.querySelector('#js-group-security-dashboard')) {
initSecurityDashboard();
} else {
initGroupDetails();
}
});
export default {
props: {
hasTriggeredBy: {
type: Boolean,
required: false,
default: false,
},
},
methods: {
buildConnnectorClass(index) {
return index === 0 && (!this.isFirstColumn || this.hasTriggeredBy) ? 'left-connector' : '';
},
},
};
......@@ -15,7 +15,7 @@ class Admin::Geo::NodesController < Admin::ApplicationController
flash.now[:alert] = _('You need a different license to enable Geo replication.')
end
unless Gitlab::Database.pg_stat_wal_receiver_supported?
unless Gitlab::Database.postgresql_minimum_supported_version?
flash.now[:warning] = _('Please upgrade PostgreSQL to version 9.6 or greater. The status of the replication cannot be determined reliably with the current version.')
end
end
......
......@@ -3,6 +3,16 @@
module EE
module GroupsController
extend ActiveSupport::Concern
extend ::Gitlab::Utils::Override
override :render_show_html
def render_show_html
if redirect_show_path
redirect_to redirect_show_path, status: :temporary_redirect
else
super
end
end
def group_params_attributes
super + group_params_ee
......@@ -25,5 +35,24 @@ module EE
def current_group
@group
end
def redirect_show_path
strong_memoize(:redirect_show_path) do
case group_view
when 'security_dashboard'
helpers.group_security_dashboard_path(group) if ::Feature.enabled?(:group_overview_security_dashboard)
else
nil
end
end
end
def group_view
current_user&.group_view || default_group_view
end
def default_group_view
EE::User::DEFAULT_GROUP_VIEW
end
end
end
# frozen_string_literal: true
class Groups::Security::ApplicationController < Groups::ApplicationController
before_action :ensure_security_dashboard_feature_enabled
before_action :ensure_security_dashboard_feature_enabled!
before_action :authorize_read_group_security_dashboard!
private
protected
def ensure_security_dashboard_feature_enabled
render_404 unless @group.feature_available?(:security_dashboard)
def ensure_security_dashboard_feature_enabled!
render_404 unless group.feature_available?(:security_dashboard)
end
def authorize_read_group_security_dashboard!
render_403 unless can?(current_user, :read_group_security_dashboard, group)
render_403 unless helpers.can_read_group_security_dashboard?(group)
end
end
......@@ -3,6 +3,7 @@
module EE
module PreferencesHelper
extend ::Gitlab::Utils::Override
include ::Groups::Security::DashboardHelper
override :excluded_dashboard_choices
def excluded_dashboard_choices
......@@ -13,9 +14,10 @@ module EE
def group_view_choices
strong_memoize(:group_view_choices) do
[[_('Details (default)'), :details]].tap do |choices|
choices << [_('Security dashboard'), :security_dashboard] if group_view_security_dashboard_enabled?
end
choices = []
choices << [_('Details (default)'), :details]
choices << [_('Security dashboard'), :security_dashboard] if group_view_security_dashboard_enabled?
choices
end
end
......
# frozen_string_literal: true
module Groups
module Security
module DashboardHelper
def can_read_group_security_dashboard?(group)
can?(current_user, :read_group_security_dashboard, group)
end
end
end
end
......@@ -68,13 +68,11 @@ module EE
::Feature.disabled?(:parse_dast_reports, default_enabled: false)
security_reports.get_report(file_type).tap do |security_report|
begin
next unless project.feature_available?(LICENSED_PARSER_FEATURES.fetch(file_type))
next unless project.feature_available?(LICENSED_PARSER_FEATURES.fetch(file_type))
::Gitlab::Ci::Parsers.fabricate!(file_type).parse!(blob, security_report)
rescue => e
security_report.error = e
end
::Gitlab::Ci::Parsers.fabricate!(file_type).parse!(blob, security_report)
rescue => e
security_report.error = e
end
end
end
......
......@@ -5,11 +5,11 @@ module EE
def rollout_status(environment)
case environment.name
when 'staging'
Gitlab::Kubernetes::RolloutStatus.new([], status: :not_found)
::Gitlab::Kubernetes::RolloutStatus.new([], status: :not_found)
when 'test'
Gitlab::Kubernetes::RolloutStatus.new([], status: :loading)
::Gitlab::Kubernetes::RolloutStatus.new([], status: :loading)
else
Gitlab::Kubernetes::RolloutStatus.new(rollout_status_deployments)
::Gitlab::Kubernetes::RolloutStatus.new(rollout_status_deployments)
end
end
......
......@@ -209,7 +209,7 @@ class GeoNodeStatus < ActiveRecord::Base
def load_secondary_data
if Gitlab::Geo.secondary?
self.db_replication_lag_seconds = Gitlab::Geo::HealthCheck.db_replication_lag_seconds
self.db_replication_lag_seconds = Gitlab::Geo::HealthCheck.new.db_replication_lag_seconds
self.cursor_last_event_id = current_cursor_last_event_id
self.cursor_last_event_date = Geo::EventLog.find_by(id: self.cursor_last_event_id)&.created_at
self.repositories_synced_count = projects_finder.count_synced_repositories
......
......@@ -144,11 +144,9 @@ module Vulnerabilities
def metadata
strong_memoize(:metadata) do
begin
JSON.parse(raw_metadata)
rescue JSON::ParserError
{}
end
JSON.parse(raw_metadata)
rescue JSON::ParserError
{}
end
end
......
......@@ -16,13 +16,11 @@ module SoftwareLicensePolicies
name = params.delete(:name)
software_license = SoftwareLicense.transaction do
begin
SoftwareLicense.transaction(requires_new: true) do
SoftwareLicense.find_or_create_by(name: name)
end
rescue ActiveRecord::RecordNotUnique
retry
SoftwareLicense.transaction(requires_new: true) do
SoftwareLicense.find_or_create_by(name: name)
end
rescue ActiveRecord::RecordNotUnique
retry
end
# Add the software license to params
......
- if can?(current_user, :read_group_security_dashboard, @group)
- if @group.feature_available?(:security_dashboard)
= nav_link(path: 'groups/security/dashboard#show') do
= link_to group_security_dashboard_path(@group), title: _('Security Dashboard') do
%span= _('Security Dashboard')
---
title: 'Geo: Only display Geo-specific clone instructions button on a Geo Secondary
node'
merge_request: 10007
author:
type: fixed
---
title: 'Geo: Support archive recovery or streaming replication types in health check'
merge_request: 9935
author:
type: fixed
---
title: Enabled setting the Security Dashboard as a default view for groups
merge_request: 7889
author:
type: added
......@@ -46,18 +46,16 @@ class FixImportDataAuthMethodForMirrors < ActiveRecord::Migration[5.0]
# Only 129 had this issue, so most of the time will be spent decrypting secrets.
# It took about 3 minutes to complete.
Project.where(mirror: true).where("import_url LIKE 'http%'").preload(:import_data).find_each do |project|
begin
import_data = project.import_data
import_data = project.import_data
next unless import_data
next unless import_data
if import_data.auth_method == 'ssh_public_key'
import_data.auth_method = 'password'
import_data.save
end
rescue OpenSSL::Cipher::CipherError
Rails.logger.warn "Error decrypting credentials in import data #{import_data&.id}"
if import_data.auth_method == 'ssh_public_key'
import_data.auth_method = 'password'
import_data.save
end
rescue OpenSSL::Cipher::CipherError
Rails.logger.warn "Error decrypting credentials in import data #{import_data&.id}"
end
end
end
......@@ -164,11 +164,9 @@ module EE
end
members.select do |dn|
begin
::Gitlab::Auth::LDAP::DN.new(dn).to_a.last(base.length) == base
rescue ::Gitlab::Auth::LDAP::DN::FormatError => e
Rails.logger.warn "Received invalid member DN from LDAP group '#{cn}': '#{dn}'. Error: \"#{e.message}\". Skipping"
end
::Gitlab::Auth::LDAP::DN.new(dn).to_a.last(base.length) == base
rescue ::Gitlab::Auth::LDAP::DN::FormatError => e
Rails.logger.warn "Received invalid member DN from LDAP group '#{cn}': '#{dn}'. Error: \"#{e.message}\". Skipping"
end
end
......
......@@ -45,15 +45,13 @@ module EE
def file_name_validation
lambda do |diff|
begin
if (diff.renamed_file || diff.new_file) && blacklisted_regex = push_rule.filename_blacklisted?(diff.new_path)
return unless blacklisted_regex.present?
"File name #{diff.new_path} was blacklisted by the pattern #{blacklisted_regex}."
end
rescue ::PushRule::MatchError => e
raise ::Gitlab::GitAccess::UnauthorizedError, e.message
if (diff.renamed_file || diff.new_file) && blacklisted_regex = push_rule.filename_blacklisted?(diff.new_path)
return unless blacklisted_regex.present?
"File name #{diff.new_path} was blacklisted by the pattern #{blacklisted_regex}."
end
rescue ::PushRule::MatchError => e
raise ::Gitlab::GitAccess::UnauthorizedError, e.message
end
end
end
......
......@@ -126,14 +126,12 @@ module Gitlab
def load
Gitlab::Geo::DatabaseTasks.with_geo_db do
begin
should_reconnect = ActiveRecord::Base.connection_pool.active_connection?
ActiveRecord::Schema.verbose = false
ActiveRecord::Tasks::DatabaseTasks.load_schema_for ActiveRecord::Base.configurations['test'], :ruby, ENV['SCHEMA']
ensure
if should_reconnect
ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations[ActiveRecord::Tasks::DatabaseTasks.env])
end
should_reconnect = ActiveRecord::Base.connection_pool.active_connection?
ActiveRecord::Schema.verbose = false
ActiveRecord::Tasks::DatabaseTasks.load_schema_for ActiveRecord::Base.configurations['test'], :ruby, ENV['SCHEMA']
ensure
if should_reconnect
ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations[ActiveRecord::Tasks::DatabaseTasks.env])
end
end
end
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment