Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
087a4d4a11
commit
4e0a9fbb9b
|
|
@ -2,16 +2,6 @@
|
|||
# Cop supports --autocorrect.
|
||||
Lint/SymbolConversion:
|
||||
Exclude:
|
||||
- 'app/controllers/groups_controller.rb'
|
||||
- 'app/controllers/projects/issues_controller.rb'
|
||||
- 'app/controllers/projects_controller.rb'
|
||||
- 'app/controllers/uploads_controller.rb'
|
||||
- 'app/graphql/mutations/members/bulk_update_base.rb'
|
||||
- 'app/graphql/mutations/snippets/base.rb'
|
||||
- 'app/graphql/resolvers/award_emoji/base_votes_count_resolver.rb'
|
||||
- 'app/graphql/resolvers/environments/last_deployment_resolver.rb'
|
||||
- 'app/graphql/resolvers/user_notes_count_resolver.rb'
|
||||
- 'app/helpers/notifications_helper.rb'
|
||||
- 'app/helpers/projects_helper.rb'
|
||||
- 'app/models/application_record.rb'
|
||||
- 'app/models/concerns/cache_markdown_field.rb'
|
||||
|
|
|
|||
1
Gemfile
1
Gemfile
|
|
@ -257,7 +257,6 @@ gem 'gitlab-active-context', path: 'gems/gitlab-active-context', require: 'activ
|
|||
gem 'html-pipeline', '~> 2.14.3', feature_category: :markdown
|
||||
gem 'deckar01-task_list', '2.3.4', feature_category: :markdown
|
||||
gem 'gitlab-markup', '~> 2.0.0', require: 'github/markup', feature_category: :markdown
|
||||
gem 'commonmarker', '~> 0.23.10', feature_category: :markdown
|
||||
gem 'kramdown', '~> 2.5.0', feature_category: :markdown
|
||||
gem 'RedCloth', '~> 4.3.3', feature_category: :markdown
|
||||
gem 'org-ruby', '~> 0.9.12', feature_category: :markdown
|
||||
|
|
|
|||
|
|
@ -447,7 +447,7 @@
|
|||
{"name":"observer","version":"0.1.2","platform":"ruby","checksum":"d8a3107131ba661138d748e7be3dbafc0d82e732fffba9fccb3d7829880950ac"},
|
||||
{"name":"octokit","version":"9.2.0","platform":"ruby","checksum":"4fa47ff35ce654127edf2c836ab9269bcc8829f5542dc1e86871f697ce7f4316"},
|
||||
{"name":"ohai","version":"18.1.18","platform":"ruby","checksum":"42ee8196945cb935fdeec93ba7aaee757d1d552f7b933912a1f25863c3cc1ff0"},
|
||||
{"name":"oj","version":"3.16.10","platform":"ruby","checksum":"7f26bed974e331e16d579b470b0865010757f6fe6ee30ea9b67df653fbe13d7c"},
|
||||
{"name":"oj","version":"3.16.11","platform":"ruby","checksum":"2aab609d2bc896529bd3c70d737f591c13932a640ba6164a0f7e414efdb052b1"},
|
||||
{"name":"oj-introspect","version":"0.8.0","platform":"ruby","checksum":"5cbb15309d60294881e5c2f65ceb22e3b5798f26d0a1e65ae47a6342b87d9264"},
|
||||
{"name":"omniauth","version":"2.1.2","platform":"ruby","checksum":"def03277298b8f8a5d3ff16cdb2eb5edb9bffed60ee7dda24cc0c89b3ae6a0ce"},
|
||||
{"name":"omniauth-alicloud","version":"3.0.0","platform":"ruby","checksum":"9c5c4f3abb40d774b946015f177d503fbde99b2b57c0858284c25cc39369013e"},
|
||||
|
|
|
|||
|
|
@ -1264,7 +1264,7 @@ GEM
|
|||
plist (~> 3.1)
|
||||
train-core
|
||||
wmi-lite (~> 1.0)
|
||||
oj (3.16.10)
|
||||
oj (3.16.11)
|
||||
bigdecimal (>= 3.0)
|
||||
ostruct (>= 0.2)
|
||||
oj-introspect (0.8.0)
|
||||
|
|
@ -2099,7 +2099,6 @@ DEPENDENCIES
|
|||
circuitbox (= 2.0.0)
|
||||
click_house-client!
|
||||
cloud_profiler_agent (~> 0.0.0)!
|
||||
commonmarker (~> 0.23.10)
|
||||
concurrent-ruby (~> 1.1)
|
||||
connection_pool (~> 2.5.3)
|
||||
countries (~> 4.0.0)
|
||||
|
|
|
|||
|
|
@ -447,7 +447,7 @@
|
|||
{"name":"observer","version":"0.1.2","platform":"ruby","checksum":"d8a3107131ba661138d748e7be3dbafc0d82e732fffba9fccb3d7829880950ac"},
|
||||
{"name":"octokit","version":"9.2.0","platform":"ruby","checksum":"4fa47ff35ce654127edf2c836ab9269bcc8829f5542dc1e86871f697ce7f4316"},
|
||||
{"name":"ohai","version":"18.1.18","platform":"ruby","checksum":"42ee8196945cb935fdeec93ba7aaee757d1d552f7b933912a1f25863c3cc1ff0"},
|
||||
{"name":"oj","version":"3.16.10","platform":"ruby","checksum":"7f26bed974e331e16d579b470b0865010757f6fe6ee30ea9b67df653fbe13d7c"},
|
||||
{"name":"oj","version":"3.16.11","platform":"ruby","checksum":"2aab609d2bc896529bd3c70d737f591c13932a640ba6164a0f7e414efdb052b1"},
|
||||
{"name":"oj-introspect","version":"0.8.0","platform":"ruby","checksum":"5cbb15309d60294881e5c2f65ceb22e3b5798f26d0a1e65ae47a6342b87d9264"},
|
||||
{"name":"omniauth","version":"2.1.2","platform":"ruby","checksum":"def03277298b8f8a5d3ff16cdb2eb5edb9bffed60ee7dda24cc0c89b3ae6a0ce"},
|
||||
{"name":"omniauth-alicloud","version":"3.0.0","platform":"ruby","checksum":"9c5c4f3abb40d774b946015f177d503fbde99b2b57c0858284c25cc39369013e"},
|
||||
|
|
|
|||
|
|
@ -1258,7 +1258,7 @@ GEM
|
|||
plist (~> 3.1)
|
||||
train-core
|
||||
wmi-lite (~> 1.0)
|
||||
oj (3.16.10)
|
||||
oj (3.16.11)
|
||||
bigdecimal (>= 3.0)
|
||||
ostruct (>= 0.2)
|
||||
oj-introspect (0.8.0)
|
||||
|
|
@ -2094,7 +2094,6 @@ DEPENDENCIES
|
|||
circuitbox (= 2.0.0)
|
||||
click_house-client!
|
||||
cloud_profiler_agent (~> 0.0.0)!
|
||||
commonmarker (~> 0.23.10)
|
||||
concurrent-ruby (~> 1.1)
|
||||
connection_pool (~> 2.5.3)
|
||||
countries (~> 4.0.0)
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ export default {
|
|||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<gl-button v-gl-modal="$options.modal.id" category="secondary">{{
|
||||
<gl-button v-gl-modal="$options.modal.id" category="secondary" size="small">{{
|
||||
$options.i18n.title
|
||||
}}</gl-button>
|
||||
<gl-modal
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ export default {
|
|||
CollapsibleSection,
|
||||
MergeRequest,
|
||||
},
|
||||
inject: ['mergeRequestsSearchDashboardPath', 'listTypeToggleEnabled'],
|
||||
inject: ['mergeRequestsSearchDashboardPath'],
|
||||
props: {
|
||||
tabs: {
|
||||
type: Array,
|
||||
|
|
@ -263,13 +263,7 @@ export default {
|
|||
</template>
|
||||
</gl-tabs>
|
||||
<div class="gl-mt-6 gl-text-center">
|
||||
<gl-link
|
||||
:href="
|
||||
listTypeToggleEnabled
|
||||
? 'https://gitlab.com/gitlab-org/gitlab/-/issues/542823'
|
||||
: 'https://gitlab.com/gitlab-org/gitlab/-/issues/515912'
|
||||
"
|
||||
>
|
||||
<gl-link href="https://gitlab.com/gitlab-org/gitlab/-/issues/542823">
|
||||
{{ __('Leave feedback') }}
|
||||
</gl-link>
|
||||
<span class="gl-mx-2">|</span>
|
||||
|
|
|
|||
|
|
@ -26,9 +26,6 @@ export default {
|
|||
preferences: {
|
||||
query: currentUserPreferencesQuery,
|
||||
update: (data) => data.currentUser.userPreferences,
|
||||
skip() {
|
||||
return !this.listTypeToggleEnabled;
|
||||
},
|
||||
},
|
||||
},
|
||||
components: {
|
||||
|
|
@ -43,7 +40,6 @@ export default {
|
|||
GlTooltip: GlTooltipDirective,
|
||||
},
|
||||
mixins: [InternalEvents.mixin()],
|
||||
inject: { listTypeToggleEnabled: { default: false } },
|
||||
data() {
|
||||
return {
|
||||
isShowingLabels: null,
|
||||
|
|
@ -53,8 +49,6 @@ export default {
|
|||
},
|
||||
computed: {
|
||||
listTypeItems() {
|
||||
if (!this.listTypeToggleEnabled) return [];
|
||||
|
||||
return [
|
||||
{
|
||||
text: __('Group by'),
|
||||
|
|
@ -147,7 +141,7 @@ export default {
|
|||
:title="__('Change display preferences')"
|
||||
no-caret
|
||||
text-sr-only
|
||||
:header-text="listTypeToggleEnabled ? __('Change display preferences') : null"
|
||||
:header-text="__('Change display preferences')"
|
||||
:toggle-text="__('Change display preferences')"
|
||||
placement="bottom-end"
|
||||
:loading="savingPreferences"
|
||||
|
|
@ -161,11 +155,7 @@ export default {
|
|||
</template>
|
||||
<template #footer>
|
||||
<div
|
||||
class="gl-flex gl-flex-col gl-px-4 gl-py-3"
|
||||
:class="{
|
||||
'gl-border-t-1 gl-border-t-dropdown-divider gl-border-t-solid': listTypeToggleEnabled,
|
||||
'toggle-labels-footer': !listTypeToggleEnabled,
|
||||
}"
|
||||
class="gl-flex gl-flex-col gl-border-t-1 gl-border-t-dropdown-divider gl-px-4 gl-py-3 gl-border-t-solid"
|
||||
>
|
||||
<local-storage-sync
|
||||
:value="isShowingLabels"
|
||||
|
|
@ -181,10 +171,7 @@ export default {
|
|||
</div>
|
||||
</template>
|
||||
</gl-collapsible-listbox>
|
||||
<user-callout-dismisser
|
||||
v-if="listTypeToggleEnabled"
|
||||
feature-name="merge_request_dashboard_display_preferences_popover"
|
||||
>
|
||||
<user-callout-dismisser feature-name="merge_request_dashboard_display_preferences_popover">
|
||||
<template #default="{ shouldShowCallout, dismiss }">
|
||||
<gl-popover
|
||||
v-if="shouldShowCallout"
|
||||
|
|
@ -212,9 +199,3 @@ export default {
|
|||
</user-callout-dismisser>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
div:has(+ .toggle-labels-footer) {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import { concatPagination } from '@apollo/client/utilities';
|
|||
import Vue from 'vue';
|
||||
import VueApollo from 'vue-apollo';
|
||||
import VueRouter from 'vue-router';
|
||||
import { parseBoolean } from '~/lib/utils/common_utils';
|
||||
import { TYPENAME_USER } from '~/graphql_shared/constants';
|
||||
import { convertToGraphQLId } from '~/graphql_shared/utils';
|
||||
import createDefaultClient from '~/lib/graphql';
|
||||
|
|
@ -104,9 +103,6 @@ export function initMergeRequestDashboard(el) {
|
|||
new Vue({
|
||||
el: document.getElementById('js-merge-request-dashboard-config'),
|
||||
apolloProvider,
|
||||
provide: {
|
||||
listTypeToggleEnabled: parseBoolean(el.dataset.listTypeToggleEnabled),
|
||||
},
|
||||
render(h) {
|
||||
return h(ConfigDropdown);
|
||||
},
|
||||
|
|
@ -118,7 +114,6 @@ export function initMergeRequestDashboard(el) {
|
|||
apolloProvider,
|
||||
provide: {
|
||||
mergeRequestsSearchDashboardPath: el.dataset.mergeRequestsSearchDashboardPath,
|
||||
listTypeToggleEnabled: parseBoolean(el.dataset.listTypeToggleEnabled),
|
||||
},
|
||||
render(createElement) {
|
||||
return createElement(App, {
|
||||
|
|
|
|||
|
|
@ -114,6 +114,12 @@
|
|||
@include str-highlighted;
|
||||
}
|
||||
|
||||
// the z-index of the mark is set to -1, so it's below the table cells
|
||||
// unless they have their own stacking context
|
||||
td:has(mark), th:has(mark) {
|
||||
isolation: isolate;
|
||||
}
|
||||
|
||||
// Fixed headings are default for markdown
|
||||
h1 {
|
||||
@apply gl-heading-1-fixed gl-mt-7 gl-pb-2 gl-border-b;
|
||||
|
|
|
|||
|
|
@ -364,7 +364,7 @@ class GroupsController < Groups::ApplicationController
|
|||
end
|
||||
|
||||
def check_export_rate_limit!
|
||||
prefixed_action = "group_#{params[:action]}".to_sym
|
||||
prefixed_action = :"group_#{params[:action]}"
|
||||
|
||||
scope = params[:action] == :download_export ? @group : nil
|
||||
|
||||
|
|
|
|||
|
|
@ -438,7 +438,7 @@ class Projects::IssuesController < Projects::ApplicationController
|
|||
errors: result.errors,
|
||||
http_status: result.http_status
|
||||
)
|
||||
error_method_name = "render_#{result.http_status}".to_sym
|
||||
error_method_name = :"render_#{result.http_status}"
|
||||
|
||||
if respond_to?(error_method_name, true)
|
||||
send(error_method_name) # rubocop:disable GitlabSecurity/PublicSend
|
||||
|
|
|
|||
|
|
@ -636,7 +636,7 @@ class ProjectsController < Projects::ApplicationController
|
|||
end
|
||||
|
||||
def check_export_rate_limit!
|
||||
prefixed_action = "project_#{params[:action]}".to_sym
|
||||
prefixed_action = :"project_#{params[:action]}"
|
||||
|
||||
project_scope = params[:action] == 'download_export' ? @project : nil
|
||||
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ class UploadsController < ApplicationController
|
|||
when Organizations::OrganizationDetail
|
||||
can?(current_user, :read_organization, model.organization)
|
||||
else
|
||||
can?(current_user, "read_#{model.class.underscore}".to_sym, model)
|
||||
can?(current_user, :"read_#{model.class.underscore}", model)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -68,11 +68,11 @@ module Mutations
|
|||
end
|
||||
|
||||
def source_id_param_name
|
||||
"#{source_name}_id".to_sym
|
||||
:"#{source_name}_id"
|
||||
end
|
||||
|
||||
def source_members_key
|
||||
"#{source_name}_members".to_sym
|
||||
:"#{source_name}_members"
|
||||
end
|
||||
|
||||
def source_name
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ module Mutations
|
|||
end
|
||||
|
||||
def ability_for(snippet)
|
||||
"#{ability_name}_#{snippet.to_ability_name}".to_sym
|
||||
:"#{ability_name}_#{snippet.to_ability_name}"
|
||||
end
|
||||
|
||||
def ability_name
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ module Resolvers
|
|||
private
|
||||
|
||||
def authorized_resource?(object)
|
||||
Ability.allowed?(current_user, "read_#{object.to_ability_name}".to_sym, object)
|
||||
Ability.allowed?(current_user, :"read_#{object.to_ability_name}", object)
|
||||
end
|
||||
|
||||
def votes_batch_loader
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ module Resolvers
|
|||
|
||||
def find_last_deployment(status)
|
||||
BatchLoader::GraphQL.for(object).batch(key: status) do |environments, loader, args|
|
||||
association_name = "last_#{args[:key]}_deployment".to_sym
|
||||
association_name = :"last_#{args[:key]}_deployment"
|
||||
|
||||
Preloaders::Environments::DeploymentPreloader.new(environments)
|
||||
.execute_with_union(association_name, {})
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ module Resolvers
|
|||
end
|
||||
|
||||
def authorized_resource?(object)
|
||||
ability = "read_#{object.class.name.underscore}".to_sym
|
||||
ability = :"read_#{object.class.name.underscore}"
|
||||
Ability.allowed?(context[:current_user], ability, object)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -566,10 +566,7 @@ module MergeRequestsHelper
|
|||
is_author_or_assignee = ::Feature.enabled?(:merge_request_dashboard_author_or_assignee, current_user,
|
||||
type: :gitlab_com_derisk)
|
||||
|
||||
if Feature.enabled?(:mr_dashboard_list_type_toggle, current_user, type: :beta) &&
|
||||
current_user.merge_request_dashboard_list_type == 'role_based'
|
||||
return merge_request_dashboard_role_based_data
|
||||
end
|
||||
return merge_request_dashboard_role_based_data if current_user.user_preference.role_based?
|
||||
|
||||
{
|
||||
tabs: [
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ module NotificationsHelper
|
|||
end
|
||||
|
||||
def show_unsubscribe_title?(noteable)
|
||||
can?(current_user, "read_#{noteable.to_ability_name}".to_sym, noteable)
|
||||
can?(current_user, :"read_#{noteable.to_ability_name}", noteable)
|
||||
end
|
||||
|
||||
def can_read_project?(project)
|
||||
|
|
|
|||
|
|
@ -87,6 +87,54 @@
|
|||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"^aws_secrets_manager$": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"secret_id"
|
||||
],
|
||||
"properties": {
|
||||
"secret_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"version_id": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"version_stage": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"region": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"role_arn": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"role_session_name": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"field": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"^akeyless$": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
@ -215,6 +263,11 @@
|
|||
"required": [
|
||||
"gitlab_secrets_manager"
|
||||
]
|
||||
},
|
||||
{
|
||||
"required": [
|
||||
"aws_secrets_manager"
|
||||
]
|
||||
}
|
||||
],
|
||||
"additionalProperties": false
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
- topic = local_assigns.fetch(:topic)
|
||||
- title = topic.title || topic.name
|
||||
|
||||
%li.topic-row.gl-py-3.gl-items-center{ class: '!gl-flex !gl-px-5' }
|
||||
%li.gl-items-center{ class: '!gl-flex' }
|
||||
= render Pajamas::AvatarComponent.new(topic, size: 32, alt: '')
|
||||
|
||||
.gl-min-w-0.gl-grow.gl-ml-3
|
||||
|
|
@ -17,5 +17,5 @@
|
|||
= number_with_delimiter(topic.total_projects_count)
|
||||
|
||||
.gl-shrink-0.gl-ml-5.gl-flex.gl-gap-3
|
||||
= link_button_to _('Edit'), edit_admin_topic_path(topic), id: "edit_#{dom_id(topic)}"
|
||||
= link_button_to _('Remove'), admin_topic_path(topic), aria: { label: _('Remove') }, data: { confirm: _("Are you sure you want to remove %{topic_name}?") % { topic_name: title }, confirm_btn_variant: 'danger' }, method: :delete, variant: :danger
|
||||
= render Pajamas::ButtonComponent.new(category: :tertiary, href: edit_admin_topic_path(topic), icon: 'pencil', button_options: { id: "edit_#{dom_id(topic)}", class: 'has-tooltip', 'title': _('Edit'), 'aria-label': _('Edit') })
|
||||
= render Pajamas::ButtonComponent.new(category: :tertiary, href: admin_topic_path(topic), method: :delete, icon: 'remove', button_options: { class: 'has-tooltip', 'title': _('Remove'), 'aria-label': _('Remove'), data: { confirm: _("Are you sure you want to remove %{topic_name}?") % { topic_name: title }, confirm_btn_variant: 'danger' } })
|
||||
|
|
|
|||
|
|
@ -7,13 +7,9 @@
|
|||
- if show_empty_state
|
||||
= render 'shared/empty_states/topics', button_text: _('New topic'), button_path: new_admin_topic_path
|
||||
- else
|
||||
= render ::Layouts::PageHeadingComponent.new(_('Topics'), options: { data: { event_tracking_load: 'true', event_tracking: 'view_admin_topics_pageload' } }) do |c|
|
||||
- c.with_actions do
|
||||
.js-merge-topics{ data: { path: merge_admin_topics_path } }
|
||||
= render Pajamas::ButtonComponent.new(href: new_admin_topic_path, variant: 'confirm') do
|
||||
= _('New topic')
|
||||
= render ::Layouts::PageHeadingComponent.new(_('Topics'), options: { data: { event_tracking_load: 'true', event_tracking: 'view_admin_topics_pageload' } })
|
||||
|
||||
.gl-flex.gl-min-w-0.gl-grow.row-content-block
|
||||
.gl-flex.gl-min-w-0.gl-grow
|
||||
= form_tag admin_topics_path, method: :get, class: 'gl-w-full' do |f|
|
||||
- search = params.fetch(:search, nil)
|
||||
.search-field-holder
|
||||
|
|
@ -23,6 +19,15 @@
|
|||
- if show_empty_search
|
||||
= render ::Layouts::EmptyResultComponent.new(type: :search)
|
||||
- else
|
||||
%ul.content-list
|
||||
= render partial: 'topic', collection: @topics
|
||||
= paginate_collection @topics
|
||||
= render ::Layouts::CrudComponent.new(_('Topics'),
|
||||
icon: 'overview',
|
||||
count: @topics.count,
|
||||
options: { class: 'gl-mt-5' }) do |c|
|
||||
- c.with_actions do
|
||||
.js-merge-topics{ data: { path: merge_admin_topics_path } }
|
||||
= render Pajamas::ButtonComponent.new(href: new_admin_topic_path, variant: 'confirm', size: 'small') do
|
||||
= _('New topic')
|
||||
- c.with_body do
|
||||
%ul.content-list
|
||||
= render partial: 'topic', collection: @topics
|
||||
= paginate_collection @topics
|
||||
|
|
|
|||
|
|
@ -34,8 +34,7 @@
|
|||
base_path: merge_requests_dashboard_path,
|
||||
merge_requests_search_dashboard_path: merge_requests_search_dashboard_path(assignee_username: current_user.username),
|
||||
initial_data: merge_request_dashboard_data.to_json,
|
||||
list_type: current_user.merge_request_dashboard_list_type,
|
||||
list_type_toggle_enabled: Feature.enabled?(:mr_dashboard_list_type_toggle, current_user, type: :beta).to_s
|
||||
list_type: current_user.merge_request_dashboard_list_type
|
||||
} }
|
||||
|
||||
- if !merge_request_dashboard_enabled?(current_user) || current_page?(merge_requests_search_dashboard_path)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
= render ::Layouts::PageHeadingComponent.new(page_title)
|
||||
|
||||
.gl-flex.gl-min-w-0.gl-grow.row-content-block
|
||||
.gl-flex.gl-min-w-0.gl-grow
|
||||
= render 'shared/topics/search_form'
|
||||
|
|
|
|||
|
|
@ -5,6 +5,11 @@
|
|||
- if show_empty_search
|
||||
= render ::Layouts::EmptyResultComponent.new(type: :search)
|
||||
- else
|
||||
%ul.content-list
|
||||
= render partial: 'shared/topics/topic', collection: @topics
|
||||
= paginate_collection @topics, remote: remote
|
||||
= render ::Layouts::CrudComponent.new(_('Topics'),
|
||||
icon: 'overview',
|
||||
count: @topics.count,
|
||||
options: { class: 'gl-mt-5' }) do |c|
|
||||
- c.with_body do
|
||||
%ul.content-list
|
||||
= render partial: 'shared/topics/topic', collection: @topics
|
||||
= paginate_collection @topics, remote: remote
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
- max_topic_title_length = 30
|
||||
- detail_page_link = topic_explore_projects_cleaned_path(topic_name: topic.name)
|
||||
|
||||
%li.topic-row.gl-py-3.gl-items-center{ class: '!gl-flex !gl-px-5' }
|
||||
%li.gl-items-center{ class: '!gl-flex' }
|
||||
= render Pajamas::AvatarComponent.new(topic, size: 32, alt: '')
|
||||
|
||||
.gl-min-w-0.gl-grow.gl-ml-3
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
name: mr_dashboard_list_type_toggle
|
||||
feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/519717
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/183805
|
||||
rollout_issue_url:
|
||||
milestone: '17.11'
|
||||
group: group::code review
|
||||
type: beta
|
||||
default_enabled: false
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddOidToLfsObjectsProjects < Gitlab::Database::Migration[2.3]
|
||||
disable_ddl_transaction!
|
||||
|
||||
milestone '18.1'
|
||||
|
||||
SOURCE_TABLE = :lfs_objects_projects
|
||||
|
||||
def up
|
||||
with_lock_retries do
|
||||
add_column SOURCE_TABLE, :oid, :text, if_not_exists: true
|
||||
end
|
||||
|
||||
add_text_limit SOURCE_TABLE, :oid, 255
|
||||
end
|
||||
|
||||
def down
|
||||
with_lock_retries do
|
||||
remove_column SOURCE_TABLE, :oid, if_exists: true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AsyncAddIndexCiBuildReportResultsOnBuildIdPartitionId < Gitlab::Database::Migration[2.3]
|
||||
milestone '18.1'
|
||||
|
||||
TABLE_NAME = :ci_build_report_results
|
||||
INDEX_NAME = :index_ci_build_report_results_on_build_id_partition_id
|
||||
COLUMNS = [:build_id, :partition_id]
|
||||
|
||||
def up
|
||||
prepare_async_index TABLE_NAME, COLUMNS, unique: true, name: INDEX_NAME
|
||||
end
|
||||
|
||||
def down
|
||||
unprepare_async_index TABLE_NAME, COLUMNS, name: INDEX_NAME
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AsyncRemoveIndexCiBuildReportResultsOnPartitionIdBuildId < Gitlab::Database::Migration[2.3]
|
||||
milestone '18.1'
|
||||
|
||||
TABLE_NAME = :ci_build_report_results
|
||||
INDEX_NAME = :index_ci_build_report_results_on_partition_id_build_id
|
||||
COLUMNS = [:partition_id, :build_id]
|
||||
|
||||
def up
|
||||
prepare_async_index_removal TABLE_NAME, COLUMNS, name: INDEX_NAME
|
||||
end
|
||||
|
||||
def down
|
||||
unprepare_async_index TABLE_NAME, COLUMNS, name: INDEX_NAME
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddIndexOfOidToLfsObjectsProjects < Gitlab::Database::Migration[2.3]
|
||||
disable_ddl_transaction!
|
||||
|
||||
milestone '18.1'
|
||||
|
||||
INDEX_NAME = 'index_lfs_objects_projects_on_oid'
|
||||
|
||||
def up
|
||||
add_concurrent_index :lfs_objects_projects, :oid, name: INDEX_NAME
|
||||
end
|
||||
|
||||
def down
|
||||
remove_concurrent_index :lfs_objects_projects, :oid, name: INDEX_NAME
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
dc035d87698c43babf8f8093c49edbc684c6f840a5457d0405c9498b5f174e70
|
||||
|
|
@ -0,0 +1 @@
|
|||
07392d9229e61122a4aa4264811246740a40c0d5039d7c99018829bd34f69329
|
||||
|
|
@ -0,0 +1 @@
|
|||
ffbd42a63d4a4c08b8e74257d865e3ddcc2f40e43cbf4a898e069be90fff2462
|
||||
|
|
@ -0,0 +1 @@
|
|||
e94d4888d721b88a874b095c08aac988e3ac1f501586417379cba65ad9bb984b
|
||||
|
|
@ -16723,7 +16723,9 @@ CREATE TABLE lfs_objects_projects (
|
|||
project_id bigint NOT NULL,
|
||||
created_at timestamp without time zone,
|
||||
updated_at timestamp without time zone,
|
||||
repository_type smallint
|
||||
repository_type smallint,
|
||||
oid text,
|
||||
CONSTRAINT check_76ef4585ad CHECK ((char_length(oid) <= 255))
|
||||
);
|
||||
|
||||
CREATE SEQUENCE lfs_objects_projects_id_seq
|
||||
|
|
@ -35814,6 +35816,8 @@ CREATE UNIQUE INDEX index_lfs_objects_on_oid ON lfs_objects USING btree (oid);
|
|||
|
||||
CREATE INDEX index_lfs_objects_projects_on_lfs_object_id ON lfs_objects_projects USING btree (lfs_object_id);
|
||||
|
||||
CREATE INDEX index_lfs_objects_projects_on_oid ON lfs_objects_projects USING btree (oid);
|
||||
|
||||
CREATE INDEX index_lfs_objects_projects_on_project_id_and_lfs_object_id ON lfs_objects_projects USING btree (project_id, lfs_object_id);
|
||||
|
||||
CREATE INDEX index_list_user_preferences_on_list_id ON list_user_preferences USING btree (list_id);
|
||||
|
|
|
|||
|
|
@ -41,9 +41,7 @@ This pipeline contains the filters for transforming raw Markdown into HTML, hand
|
|||
|
||||
#### `Filter::MarkdownFilter`
|
||||
|
||||
This filter interfaces with the actual Markdown parser. The primary parser uses our [`gitlab-glfm-markdown`](https://gitlab.com/gitlab-org/ruby/gems/gitlab-glfm-markdown) Ruby gem that uses the [`comrak`](https://github.com/kivikakk/comrak) Rust crate.
|
||||
|
||||
A secondary deprecated parser engine uses the [`commonmarker`](https://github.com/gjtorikian/commonmarker/releases/tag/v0.23.11) Ruby gem to interact with the [`cmark-gfm`](https://github.com/github/cmark-gfm) library.
|
||||
This filter interfaces with the actual Markdown parser. The parser uses our [`gitlab-glfm-markdown`](https://gitlab.com/gitlab-org/ruby/gems/gitlab-glfm-markdown) Ruby gem that uses the [`comrak`](https://github.com/kivikakk/comrak) Rust crate.
|
||||
|
||||
Text is passed into this filter, and by calling the specified parser engine, generates the corresponding basic HTML.
|
||||
|
||||
|
|
|
|||
|
|
@ -401,7 +401,7 @@ This ensures your policy always reflects the most current Blue Oak Council licen
|
|||
|
||||
### Policy not applying
|
||||
|
||||
Ensure the security policy project you modified is correctly linked to your group. See [Link to a security policy project](../../user/application_security/policies/_index.md#link-to-a-security-policy-project) for more.
|
||||
Ensure the security policy project you modified is correctly linked to your group. See [Link to a security policy project](../../user/application_security/policies/security_policy_projects.md#link-to-a-security-policy-project) for more.
|
||||
|
||||
### Dependency scan not running
|
||||
|
||||
|
|
|
|||
|
|
@ -161,4 +161,4 @@ An example password in clear is shown below:
|
|||
|
||||
### Policy not applying
|
||||
|
||||
Ensure the security policy project you modified is correctly linked to your group. See [Link to a security policy project](../../user/application_security/policies/_index.md#link-to-a-security-policy-project) for more.
|
||||
Ensure the security policy project you modified is correctly linked to your group. See [Link to a security policy project](../../user/application_security/policies/security_policy_projects.md#link-to-a-security-policy-project) for more.
|
||||
|
|
|
|||
|
|
@ -41,42 +41,7 @@ The following policy types are available:
|
|||
- [Vulnerability management policy](vulnerability_management_policy.md). Automatically resolve
|
||||
vulnerabilities that are no longer detected in the default branch.
|
||||
|
||||
## Security policy project
|
||||
|
||||
A security policy project is a special type of project used only to contain policies. The
|
||||
policies are stored in the `.gitlab/security-policies/policy.yml` YAML file.
|
||||
|
||||
To enforce the policies contained in a security policy project, link the security policy
|
||||
project to the projects, subgroups, or groups you want to enforce the policies on.
|
||||
A security policy project can contain multiple policies but they are
|
||||
enforced together. A security policy project enforced on a group or subgroup applies to everything
|
||||
below in the hierarchy, including all subgroups and their projects.
|
||||
|
||||
Policy changes made in a merge request take effect as soon as the merge request is merged. Those
|
||||
that do not go through a merge request, but instead are committed directly to the default branch,
|
||||
may require up to 10 minutes before the policy changes take effect.
|
||||
|
||||
## Deleting security policy projects
|
||||
|
||||
{{< history >}}
|
||||
|
||||
- The deletion protection for security policy projects was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/482967) in GitLab 17.8 [with a flag](../../../administration/feature_flags.md) named `reject_security_policy_project_deletion`. Enabled by default.
|
||||
- The deletion protection for groups that contain security policy projects was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/512043) in GitLab 17.9 [with a flag](../../../administration/feature_flags.md) named `reject_security_policy_project_deletion_groups`. Enabled by default.
|
||||
- The deletion protection for security policy projects is generally available in GitLab 17.10. Feature flag `reject_security_policy_project_deletion` removed.
|
||||
- The deletion protection for groups that contain security policy projects is generally available in GitLab 17.10. Feature flag `reject_security_policy_project_deletion_groups` removed.
|
||||
|
||||
{{< /history >}}
|
||||
|
||||
{{< alert type="flag" >}}
|
||||
|
||||
The availability of this feature is controlled by a feature flag.
|
||||
For more information, see the history.
|
||||
|
||||
{{< /alert >}}
|
||||
|
||||
To delete a security policy project or one of its parent groups, you must remove the link to it
|
||||
from all other projects or groups. Otherwise, an error message is displayed when you attempt
|
||||
to delete a linked security policy project or a parent group.
|
||||
To enforce policies across multiple projects, use [security policy projects](security_policy_projects.md). A security policy project is a special type of project used only to contain policies. To enforce the policies from a security policy project in other groups and projects, link to the security policy project from groups or other projects.
|
||||
|
||||
## Policy design guidelines
|
||||
|
||||
|
|
@ -280,147 +245,6 @@ If you're not a group member, you may face limitations in adding or editing poli
|
|||
|
||||
{{< /alert >}}
|
||||
|
||||
## Policy implementation
|
||||
|
||||
Implementation options for security policy projects differ slightly between GitLab.com, GitLab
|
||||
Dedicated, and GitLab Self-Managed. The main difference is that on GitLab.com it's only possible to
|
||||
create subgroups. Ensuring separation of duties requires more granular permission configuration.
|
||||
|
||||
### Enforce policies globally in your GitLab.com namespace
|
||||
|
||||
{{< details >}}
|
||||
|
||||
- Tier: Ultimate
|
||||
- Offering: GitLab.com
|
||||
|
||||
{{< /details >}}
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- You must have the Owner role or [custom role](../../custom_roles/_index.md) with the
|
||||
`manage_security_policy_link` permission to link to the security policy project. For more
|
||||
information, see [separation of duties](#separation-of-duties).
|
||||
|
||||
The high-level workflow for enforcing policies globally across all subgroups and projects in your GitLab.com namespace:
|
||||
|
||||
1. Visit the **Policies** tab from your top-level group.
|
||||
1. In the subgroup, go to the **Policies** tab and create a test policy.
|
||||
|
||||
(Tip: You can create a policy as disabled for testing.) Creating the policy automatically creates
|
||||
a new security policy project under your top-level group. This project is used to store your
|
||||
`policy.yml` or policy-as-code.
|
||||
1. Check and set permissions in the newly created project as desired.
|
||||
|
||||
By default, Owners and Maintainers are able to create, edit, and delete policies. Developers can
|
||||
propose policy changes but cannot merge them.
|
||||
1. In the security policy project created within your subgroup, create the policies required.
|
||||
|
||||
You can use the policy editor in the `Security Policy Management` project you created, under the
|
||||
**Policies** tab. Or you can directly update the policies in the `policy.yml` file stored in the
|
||||
newly-created security policy project `Security Policy Management - security policy project`.
|
||||
1. Link up groups, subgroups, or projects to the security policy project.
|
||||
|
||||
As a subgroup owner, or project owner with proper permissions, you can visit the **Policies**
|
||||
page and create a link to the security policy project. Include the full path and the project's
|
||||
name should end with "- security policy project". All linked groups, subgroups, and projects
|
||||
become "enforceable" by any policies created in the security policy project. For details, see
|
||||
[Link to a security policy project](#link-to-a-security-policy-project).
|
||||
1. By default, when a policy is enabled, it is enforced on all projects in linked groups,
|
||||
subgroups, and projects.
|
||||
|
||||
For more granular enforcement, add a "policy scope". Policy scopes allow you to enforce policies
|
||||
against a specific set of projects or against projects containing a given set of compliance
|
||||
framework labels.
|
||||
1. If you need additional restrictions, for example to block inherited permissions or require
|
||||
additional review or approval of policy changes, you can create an additional policy scoped only
|
||||
to your security policy project and enforce additional approvals.
|
||||
|
||||
### Enforce policies globally in GitLab Dedicated or GitLab Self-Managed
|
||||
|
||||
{{< details >}}
|
||||
|
||||
- Tier: Ultimate
|
||||
- Offering: GitLab Self-Managed, GitLab Dedicated
|
||||
|
||||
{{< /details >}}
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- You must have the Owner role or [custom role](../../custom_roles/_index.md) with the
|
||||
`manage_security_policy_link` permission to link to the security policy project. For more
|
||||
information, see [separation of duties](#separation-of-duties).
|
||||
- To support approval groups globally across your instance, enable
|
||||
`security_policy_global_group_approvers_enabled` in your
|
||||
[GitLab instance application settings](../../../api/settings.md).
|
||||
|
||||
The high-level workflow for enforcing policies across multiple groups:
|
||||
|
||||
1. Create a separate group to contain your policies and ensure separation of duties.
|
||||
|
||||
By creating a separate standalone group, you can minimize the number of users who inherit
|
||||
permissions.
|
||||
1. In the new group, visit the **Policies** tab.
|
||||
|
||||
This serves as the primary location of the policy editor, allowing you to
|
||||
create and manage policies in the UI.
|
||||
1. Create a test policy (you can create a policy as disabled for testing).
|
||||
|
||||
Creating the policy automatically creates a new security policy project under your group. This
|
||||
project is used to store your `policy.yml` or policy-as-code.
|
||||
1. Check and set permissions in the newly created project as desired.
|
||||
|
||||
By default, Owners and Maintainers are able to create, edit, and delete policies. Developers can
|
||||
propose policy changes but cannot merge them.
|
||||
1. In the security policy project created in your subgroup, create the policies required.
|
||||
|
||||
You can use the policy editor in the `Security Policy Management` project you created, under the
|
||||
Policies tab. Or you can directly update the policies in the `policy.yml` file stored in the
|
||||
newly-created security policy project `Security Policy Management - security policy project`.
|
||||
1. Link up groups, subgroups, or projects to the security policy project.
|
||||
|
||||
As a subgroup owner, or project owner with proper permissions, you can visit the **Policies**
|
||||
page and create a link to the security policy project. Include the full path and the project's
|
||||
name should end with "-security policy project". All linked groups, subgroups, and projects
|
||||
become "enforceable" by any policies created in the security policy project. For more information, see
|
||||
[link to a security policy project](#link-to-a-security-policy-project).
|
||||
1. By default, when a policy is enabled, it is enforced on all projects in linked groups, subgroups,
|
||||
and projects. For more granular enforcement, add a policy scope. Policy scopes allow you to
|
||||
enforce policies against a specific set of projects or against projects containing a given set of
|
||||
compliance framework labels.
|
||||
1. If you need additional restrictions, for example to block inherited permissions or require
|
||||
additional review or approval of policy changes, you can create an additional policy scoped only
|
||||
to your security policy project and enforce additional approvals.
|
||||
|
||||
## Link to a security policy project
|
||||
|
||||
To enforce the policies contained in a security policy project against a group, subgroup, or
|
||||
project, you link them. By default, all linked entities are enforced. To enforce policies
|
||||
granularly per policy, you can set a "policy scope" in each policy.
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- You must have the Owner role or [custom role](../../custom_roles/_index.md) with the`manage_security_policy_link` permission to link to the security policy project. For more information, see [separation of duties](#separation-of-duties).
|
||||
- You must have at least the Reporter role or [custom role](../../custom_roles/_index.md) with the `manage_security_policy_link` permission to the project you want to assign as the security policy project. For more information, see [separation of duties](#separation-of-duties).
|
||||
|
||||
To link a group, subgroup, or project to a security policy project:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your project, subgroup, or group.
|
||||
1. Select **Secure > Policies**.
|
||||
1. Select **Edit Policy Project**, then search for and select the project you would like to link
|
||||
from the dropdown list.
|
||||
1. Select **Save**.
|
||||
|
||||
To unlink a security policy project, follow the same steps but instead select the trash can icon in
|
||||
the dialog.
|
||||
You can link to a security policy project from a different subgroup in the same top-level group, or from an entirely different top-level group.
|
||||
However, when you enforce a
|
||||
[pipeline execution policy](pipeline_execution_policies.md#pipeline-execution-policy-schema), users must have at least read-only access to the project that contains the CI/CD configuration referenced in the policy to trigger the pipeline.
|
||||
|
||||
### Viewing the linked security policy project
|
||||
|
||||
All users who have access to the project policy page and are not project owners instead view a
|
||||
button linking out to the associated security policy project.
|
||||
|
||||
## Policy recommendations
|
||||
|
||||
When implementing policies, consider the following recommendations.
|
||||
|
|
|
|||
|
|
@ -450,7 +450,7 @@ The availability of support for pipeline execution policies is controlled by a f
|
|||
#### Example of `policy_tuning` with a scan execution policy
|
||||
|
||||
You can use this example in a `.gitlab/security-policies/policy.yml` file stored in a
|
||||
[security policy project](_index.md#security-policy-project):
|
||||
[security policy project](security_policy_projects.md):
|
||||
|
||||
```yaml
|
||||
scan_execution_policy:
|
||||
|
|
@ -504,7 +504,7 @@ For more information, see [Recreate pipeline execution policies created before G
|
|||
{{< /alert >}}
|
||||
|
||||
You can use this example in a `.gitlab/security-policies/policy.yml` file stored in a
|
||||
[security policy project](_index.md#security-policy-project):
|
||||
[security policy project](security_policy_projects.md):
|
||||
|
||||
```yaml
|
||||
---
|
||||
|
|
@ -559,7 +559,7 @@ specified projects, groups, or compliance framework labels. For more details, se
|
|||
## Example `policy.yml` in a security policy project
|
||||
|
||||
You can use this example in a `.gitlab/security-policies/policy.yml` file stored in a
|
||||
[security policy project](_index.md#security-policy-project):
|
||||
[security policy project](security_policy_projects.md):
|
||||
|
||||
```yaml
|
||||
---
|
||||
|
|
|
|||
|
|
@ -815,7 +815,7 @@ These examples demonstrate what you can achieve with pipeline execution policies
|
|||
### Pipeline execution policy
|
||||
|
||||
You can use the following example in a `.gitlab/security-policies/policy.yml` file stored in a
|
||||
[security policy project](_index.md#security-policy-project):
|
||||
[security policy project](security_policy_projects.md):
|
||||
|
||||
```yaml
|
||||
---
|
||||
|
|
|
|||
|
|
@ -469,7 +469,7 @@ specified projects, groups, or compliance framework labels. For more details, se
|
|||
## Example security policy project
|
||||
|
||||
You can use this example in a `.gitlab/security-policies/policy.yml` file stored in a
|
||||
[security policy project](_index.md#security-policy-project):
|
||||
[security policy project](security_policy_projects.md):
|
||||
|
||||
```yaml
|
||||
---
|
||||
|
|
|
|||
|
|
@ -0,0 +1,182 @@
|
|||
---
|
||||
stage: Security Risk Management
|
||||
group: Security Policies
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
description: Learn how to enforce security rules in GitLab using merge request approval policies to automate scans, approvals, and compliance across your projects.
|
||||
title: Security policy projects
|
||||
---
|
||||
|
||||
{{< details >}}
|
||||
|
||||
- Tier: Ultimate
|
||||
- Offering: GitLab.com, GitLab Self-Managed, GitLab Dedicated
|
||||
|
||||
{{< /details >}}
|
||||
|
||||
Security policy projects enforce policies across multiple projects. A security policy project is a
|
||||
special type of project used only to contain policies. To enforce the policies contained in a
|
||||
security policy project, link the security policy project to the projects, subgroups, or groups
|
||||
you want to enforce the policies on. A security policy project can contain multiple policies but they are
|
||||
enforced together. A security policy project enforced on a group or subgroup applies to everything
|
||||
below in the hierarchy, including all subgroups and their projects.
|
||||
|
||||
Policy changes made in a merge request take effect as soon as the merge request is merged. Those
|
||||
that do not go through a merge request, but instead are committed directly to the default branch,
|
||||
may require up to 10 minutes before the policy changes take effect.
|
||||
|
||||
Policies are stored in the `.gitlab/security-policies/policy.yml` YAML file.
|
||||
|
||||
## Security policy project implementation
|
||||
|
||||
Implementation options for security policy projects differ slightly between GitLab.com, GitLab
|
||||
Dedicated, and GitLab Self-Managed. The main difference is that on GitLab.com it's only possible to
|
||||
create subgroups. Ensuring separation of duties requires more granular permission configuration.
|
||||
|
||||
### Enforce policies globally in your GitLab.com namespace
|
||||
|
||||
{{< details >}}
|
||||
|
||||
- Tier: Ultimate
|
||||
- Offering: GitLab.com
|
||||
|
||||
{{< /details >}}
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- You must have the Owner role or a [custom role](../../custom_roles/_index.md) with the
|
||||
`manage_security_policy_link` permission to link to the security policy project. For more
|
||||
information, see [separation of duties](_index.md#separation-of-duties).
|
||||
|
||||
The high-level workflow for enforcing policies globally across all subgroups and projects in your GitLab.com namespace:
|
||||
|
||||
1. Visit the **Policies** tab from your top-level group.
|
||||
1. In the subgroup, go to the **Policies** tab and create a test policy.
|
||||
|
||||
You can create a policy as disabled for testing. Creating the policy automatically creates
|
||||
a new security policy project under your top-level group. This project is used to store your
|
||||
`policy.yml` or policy-as-code.
|
||||
1. Check and set permissions in the newly created project as desired.
|
||||
|
||||
By default, Owners and Maintainers are able to create, edit, and delete policies. Developers can
|
||||
propose policy changes but cannot merge them.
|
||||
1. In the security policy project created within your subgroup, create the policies required.
|
||||
|
||||
You can use the policy editor in the `Security Policy Management` project you created, under the
|
||||
**Policies** tab. Or you can directly update the policies in the `policy.yml` file stored in the
|
||||
newly-created security policy project `Security Policy Management - security policy project`.
|
||||
1. Link up groups, subgroups, or projects to the security policy project.
|
||||
|
||||
As a subgroup owner, or project owner with proper permissions, you can visit the **Policies**
|
||||
page and create a link to the security policy project. Include the full path and the project's
|
||||
name should end with "- security policy project". All linked groups, subgroups, and projects
|
||||
become "enforceable" by any policies created in the security policy project. For details, see
|
||||
[Link to a security policy project](#link-to-a-security-policy-project).
|
||||
1. By default, when a policy is enabled, it is enforced on all projects in linked groups,
|
||||
subgroups, and projects.
|
||||
|
||||
For more granular enforcement, add a policy scope. A policy scope allow you to enforce policies
|
||||
against a specific set of projects or against projects containing a set of compliance
|
||||
framework labels.
|
||||
1. If you need additional restrictions, for example to block inherited permissions or require
|
||||
additional review or approval of policy changes, you can create an additional policy scoped only
|
||||
to your security policy project and enforce additional approvals.
|
||||
|
||||
### Enforce policies globally in GitLab Dedicated or GitLab Self-Managed
|
||||
|
||||
{{< details >}}
|
||||
|
||||
- Tier: Ultimate
|
||||
- Offering: GitLab Self-Managed, GitLab Dedicated
|
||||
|
||||
{{< /details >}}
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- You must have the Owner role or a [custom role](../../custom_roles/_index.md) with the
|
||||
`manage_security_policy_link` permission to link to the security policy project. For more
|
||||
information, see [separation of duties](_index.md#separation-of-duties).
|
||||
- To support approval groups globally across your instance, enable
|
||||
`security_policy_global_group_approvers_enabled` in your
|
||||
[GitLab instance application settings](../../../api/settings.md).
|
||||
|
||||
The high-level workflow for enforcing policies across multiple groups:
|
||||
|
||||
1. Create a separate group to contain your policies and ensure separation of duties.
|
||||
|
||||
By creating a separate standalone group, you can minimize the number of users who inherit
|
||||
permissions.
|
||||
1. In the new group, visit the **Policies** tab.
|
||||
|
||||
This serves as the primary location of the policy editor, allowing you to
|
||||
create and manage policies in the UI.
|
||||
1. Create a test policy (you can create a policy as disabled for testing).
|
||||
|
||||
Creating the policy automatically creates a new security policy project under your group. This
|
||||
project is used to store your `policy.yml` or policy-as-code.
|
||||
1. Check and set permissions in the newly created project as desired.
|
||||
|
||||
By default, Owners and Maintainers are able to create, edit, and delete policies. Developers can
|
||||
propose policy changes but cannot merge them.
|
||||
1. In the security policy project created in your subgroup, create the policies required.
|
||||
|
||||
You can use the policy editor in the `Security Policy Management` project you created, under the
|
||||
Policies tab. Or you can directly update the policies in the `policy.yml` file stored in the
|
||||
newly-created security policy project `Security Policy Management - security policy project`.
|
||||
1. Link up groups, subgroups, or projects to the security policy project.
|
||||
|
||||
As a subgroup owner, or project owner with proper permissions, you can visit the **Policies**
|
||||
page and create a link to the security policy project. Include the full path and the project's
|
||||
name should end with "- security policy project". All linked groups, subgroups, and projects
|
||||
become "enforceable" by any policies created in the security policy project. For more information, see
|
||||
[link to a security policy project](#link-to-a-security-policy-project).
|
||||
1. By default, when a policy is enabled, it is enforced on all projects in linked groups, subgroups,
|
||||
and projects. For more granular enforcement, add a policy scope. A policy scope allows you to
|
||||
enforce policies against a specific set of projects or against projects that contain a set of
|
||||
compliance framework labels.
|
||||
1. If you need additional restrictions, for example to block inherited permissions or require
|
||||
additional review or approval of policy changes, you can create an additional policy scoped only
|
||||
to your security policy project and enforce additional approvals.
|
||||
|
||||
## Link to a security policy project
|
||||
|
||||
To enforce the policies contained in a security policy project against a group, subgroup, or
|
||||
project, you link them. By default, all linked entities are enforced. To enforce policies
|
||||
granularly per policy, you can set a policy scope in each policy.
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- You must have the Owner role or [custom role](../../custom_roles/_index.md) with the`manage_security_policy_link` permission to link to the security policy project. For more information, see [separation of duties](_index.md#separation-of-duties).
|
||||
- You must have at least the Reporter role or [custom role](../../custom_roles/_index.md) with the `manage_security_policy_link` permission to the project you want to assign as the security policy project. For more information, see [separation of duties](_index.md#separation-of-duties).
|
||||
|
||||
To link a group, subgroup, or project to a security policy project:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your project, subgroup, or group.
|
||||
1. Select **Secure > Policies**.
|
||||
1. Select **Edit Policy Project**, then search for and select the project you would like to link
|
||||
from the dropdown list.
|
||||
1. Select **Save**.
|
||||
|
||||
To unlink a security policy project, follow the same steps but instead select the trash can icon in
|
||||
the dialog.
|
||||
You can link to a security policy project from a different subgroup in the same top-level group, or from an entirely different top-level group.
|
||||
However, when you enforce a
|
||||
[pipeline execution policy](pipeline_execution_policies.md#pipeline-execution-policy-schema), users must have at least read-only access to the project that contains the CI/CD configuration referenced in the policy to trigger the pipeline.
|
||||
|
||||
### Viewing the linked security policy project
|
||||
|
||||
All users who have access to the project policy page and are not project owners instead view a
|
||||
button linking out to the associated security policy project.
|
||||
|
||||
## Deleting a security policy project
|
||||
|
||||
{{< history >}}
|
||||
|
||||
- Deletion protection for security policy projects was introduced in GitLab 17.8 with a flag named `reject_security_policy_project_deletion`. Enabled by default.
|
||||
- Deletion protection for groups that contain security policy projects was introduced in GitLab 17.9 with a flag named `reject_security_policy_project_deletion_groups`. Enabled by default.
|
||||
- Deletion protection for security policy projects and groups that contain security policy projects is generally available in GitLab 17.10. Feature flags `reject_security_policy_project_deletion` and `reject_security_policy_project_deletion_groups` removed.
|
||||
|
||||
{{< /history >}}
|
||||
|
||||
To delete a security policy project or one of its parent groups, you must remove the link to it
|
||||
from all other projects or groups. Otherwise, an error message is displayed when you attempt
|
||||
to delete a linked security policy project or a parent group.
|
||||
|
|
@ -70,7 +70,7 @@ To migrate an existing compliance framework to use the pipeline execution policy
|
|||
1. In the banner than appears, select **Migrate pipeline to a policy** to create a new policy in the security policies.
|
||||
1. Edit the compliance framework again to remove the compliance pipeline.
|
||||
|
||||
For more information, see [Security policy project](../application_security/policies/_index.md#security-policy-project).
|
||||
For more information, see [Security policy project](../application_security/policies/security_policy_projects.md).
|
||||
|
||||
If you receive a `Pipeline execution policy error: Job names must be unique` error during the migration, see the
|
||||
[relevant troubleshooting information](#error-job-names-must-be-unique).
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ Create a license approval policy to enforce license compliance.
|
|||
|
||||
To create a license approval policy:
|
||||
|
||||
1. [Link a security policy project](../application_security/policies/_index.md#policy-implementation) to your development group, subgroup, or project (the Owner role is required).
|
||||
1. [Link a security policy project](../application_security/policies/security_policy_projects.md#link-to-a-security-policy-project) to your development group, subgroup, or project (the Owner role is required).
|
||||
1. On the left sidebar, select **Search or go to** and find your project.
|
||||
1. Select **Secure > Policies**.
|
||||
1. Create a new [Merge request approval Policy](../application_security/policies/merge_request_approval_policies.md).
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ module Banzai
|
|||
end
|
||||
|
||||
# Since this came from a Text node, make sure the new href is encoded.
|
||||
# `commonmarker` percent encodes the domains of links it handles, so
|
||||
# Markdown renderer percent encodes the domains of links it handles, so
|
||||
# do the same (instead of using `normalized_encode`).
|
||||
begin
|
||||
href_safe = Addressable::URI.encode(match).html_safe
|
||||
|
|
|
|||
|
|
@ -41,14 +41,14 @@ module Banzai
|
|||
pre_node.set_attribute(LANG_ATTR, escape_once(lang)) if lang.present?
|
||||
pre_node.set_attribute(LANG_PARAMS_ATTR, escape_once(lang_params)) if lang_params.present?
|
||||
|
||||
# cmark-gfm added this, it's now in data-lang-params
|
||||
# markdown rendered added this, it's now in data-lang-params
|
||||
pre_node.remove_attribute('data-meta')
|
||||
code_node.remove_attribute('data-meta')
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# cmark-gfm's FULL_INFO_STRING render option works with the space delimiter.
|
||||
# the `full_info_string` render option works with the space delimiter.
|
||||
# Which means the language specified on a code block is parsed with spaces. Anything
|
||||
# after the first space is placed in the `data-meta` attribute.
|
||||
# However GitLab recognizes `:` as an additional delimiter on the lang attribute.
|
||||
|
|
@ -67,7 +67,7 @@ module Banzai
|
|||
|
||||
language, language_params = language.split(LANG_PARAMS_DELIMITER, 2)
|
||||
|
||||
# cmark-gfm places extra lang parameters into data-meta
|
||||
# markdown renderer places extra lang parameters into data-meta
|
||||
language_params = [pre_node.attr('data-meta'), code_node.attr('data-meta'), language_params].compact.join(' ')
|
||||
|
||||
[language, language_params]
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
module Banzai
|
||||
module Filter
|
||||
# HTML Filter for parsing Gollum's tags in HTML.
|
||||
# Only used for the ascii_doc pipeline or the older cmark parser.
|
||||
# Only used for the ascii_doc pipeline.
|
||||
#
|
||||
# It's only parses the following tags:
|
||||
#
|
||||
|
|
@ -35,7 +35,7 @@ module Banzai
|
|||
IGNORED_ANCESTOR_TAGS = %w[pre code tt].to_set
|
||||
|
||||
def call
|
||||
return doc if MarkdownFilter.glfm_markdown?(context) && context[:pipeline] != :ascii_doc
|
||||
return doc if context[:pipeline] != :ascii_doc
|
||||
|
||||
doc.xpath('descendant-or-self::text()').each do |node|
|
||||
next if has_ancestor?(node, IGNORED_ANCESTOR_TAGS)
|
||||
|
|
|
|||
|
|
@ -1,51 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# `CommonMark` markdown engine for GitLab's Banzai markdown filter.
|
||||
# This module is used in Banzai::Filter::MarkdownFilter.
|
||||
# Used gem is `commonmarker` which is a ruby wrapper for cmark-gfm (CommonMark parser)
|
||||
# including GitHub's GFM extensions.
|
||||
# We now utilize the renderer built in `C`, rather than the ruby based renderer.
|
||||
# Homepage: https://github.com/gjtorikian/commonmarker
|
||||
#
|
||||
# Although this engine is currently not actively used, let's keep it here
|
||||
# for performance testing and as a backup.
|
||||
module Banzai
|
||||
module Filter
|
||||
module MarkdownEngines
|
||||
class Cmark < Base
|
||||
EXTENSIONS = [
|
||||
:autolink, # provides support for automatically converting URLs to anchor tags.
|
||||
:strikethrough, # provides support for strikethroughs.
|
||||
:table # provides support for tables.
|
||||
].freeze
|
||||
|
||||
PARSE_OPTIONS = [
|
||||
:FOOTNOTES, # parse footnotes.
|
||||
:STRIKETHROUGH_DOUBLE_TILDE, # parse strikethroughs by double tildes (as redcarpet does).
|
||||
:VALIDATE_UTF8 # replace illegal sequences with the replacement character U+FFFD.
|
||||
].freeze
|
||||
|
||||
RENDER_OPTIONS = [
|
||||
:GITHUB_PRE_LANG, # use GitHub-style <pre lang> for fenced code blocks.
|
||||
:FOOTNOTES, # render footnotes.
|
||||
:FULL_INFO_STRING, # include full info strings of code blocks in separate attribute.
|
||||
:UNSAFE # allow raw/custom HTML and unsafe links.
|
||||
].freeze
|
||||
|
||||
RENDER_OPTIONS_SOURCEPOS = RENDER_OPTIONS + [:SOURCEPOS].freeze
|
||||
|
||||
def render(text)
|
||||
CommonMarker.render_html(text, render_options, EXTENSIONS)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def render_options
|
||||
sourcepos_disabled? ? RENDER_OPTIONS : RENDER_OPTIONS_SOURCEPOS
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Banzai::Filter::MarkdownEngines::Cmark.prepend_mod
|
||||
|
|
@ -4,7 +4,6 @@ module Banzai
|
|||
module Filter
|
||||
class MarkdownFilter < HTML::Pipeline::TextFilter
|
||||
GLFM_ENGINE = :glfm_markdown # glfm_markdown/comrak
|
||||
CMARK_ENGINE = :cmark # original commonmarker/cmark-gfm
|
||||
DEFAULT_ENGINE = GLFM_ENGINE
|
||||
|
||||
def initialize(text, context = nil, result = nil)
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@
|
|||
- i_ci_secrets_management_id_tokens_build_created
|
||||
- i_ci_secrets_management_vault_build_created
|
||||
- i_ci_secrets_management_gitlab_secrets_manager_build_created
|
||||
- i_ci_secrets_management_aws_secrets_manager_build_created
|
||||
- i_code_review_click_diff_view_setting
|
||||
- i_code_review_click_file_browser_setting
|
||||
- i_code_review_click_single_file_mode_setting
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ RSpec.describe 'GitLab Markdown Benchmark', :aggregate_failures, feature_categor
|
|||
let_it_be(:wiki_page) { feature.wiki_page }
|
||||
let_it_be(:markdown_text) { feature.raw_markdown }
|
||||
let_it_be(:glfm_engine) { Banzai::Filter::MarkdownFilter::GLFM_ENGINE }
|
||||
let_it_be(:cmark_engine) { Banzai::Filter::MarkdownFilter::CMARK_ENGINE }
|
||||
let_it_be(:grafana_integration) { create(:grafana_integration, project: project) }
|
||||
let_it_be(:default_context) do
|
||||
{
|
||||
|
|
@ -85,33 +84,31 @@ RSpec.describe 'GitLab Markdown Benchmark', :aggregate_failures, feature_categor
|
|||
|
||||
context 'markdown engines' do
|
||||
it 'benchmarks full pipeline using different markdown engines' do
|
||||
puts "\n--> Benchmarking FullPipeline with Cmark and Glfm engines\n"
|
||||
puts "\n--> Benchmarking FullPipeline with Glfm engine\n"
|
||||
|
||||
Benchmark.ips do |x|
|
||||
x.config(time: 10, warmup: 2)
|
||||
|
||||
x.report('glfm') { Banzai::Pipeline::FullPipeline.call(markdown_text, context.merge(markdown_engine: glfm_engine)) }
|
||||
x.report('cmark') { Banzai::Pipeline::FullPipeline.call(markdown_text, context.merge(markdown_engine: cmark_engine)) }
|
||||
|
||||
x.compare!
|
||||
end
|
||||
end
|
||||
|
||||
it 'benchmarks plain markdown pipeline using different markdown engines' do
|
||||
puts "\n--> Benchmarking PlainMarkdownPipeline with Cmark and Glfm engines\n"
|
||||
puts "\n--> Benchmarking PlainMarkdownPipeline with Glfm engine\n"
|
||||
|
||||
Benchmark.ips do |x|
|
||||
x.config(time: 10, warmup: 2)
|
||||
|
||||
x.report('glfm') { Banzai::Pipeline::PlainMarkdownPipeline.call(markdown_text, context.merge(markdown_engine: glfm_engine)) }
|
||||
x.report('cmark') { Banzai::Pipeline::PlainMarkdownPipeline.call(markdown_text, context.merge(markdown_engine: cmark_engine)) }
|
||||
|
||||
x.compare!
|
||||
end
|
||||
end
|
||||
|
||||
it 'benchmarks MarkdownFilter using different markdown engines' do
|
||||
puts "\n--> Benchmarking MarkdownFilter with Cmark and Glfm engines\n"
|
||||
puts "\n--> Benchmarking MarkdownFilter with Glfm engine\n"
|
||||
|
||||
pipeline = Banzai::Pipeline[:plain_markdown]
|
||||
filter_klass = Banzai::Filter::MarkdownFilter
|
||||
|
|
@ -127,13 +124,6 @@ RSpec.describe 'GitLab Markdown Benchmark', :aggregate_failures, feature_categor
|
|||
filter.call
|
||||
end
|
||||
|
||||
x.report('Markdown-cmark') do
|
||||
filter = filter_klass.new(filter_source[filter_klass][:input_text],
|
||||
context.merge(markdown_engine: cmark_engine),
|
||||
filter_source[filter_klass][:input_result])
|
||||
filter.call
|
||||
end
|
||||
|
||||
x.compare!
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -25,13 +25,12 @@ describe('Merge requests app component', () => {
|
|||
const findMergeRequests = () => wrapper.findAllComponents(MergeRequest);
|
||||
const findLoadMoreButton = () => wrapper.findByTestId('load-more');
|
||||
const findCountExplanation = () => wrapper.findByTestId('merge-request-count-explanation');
|
||||
const findFeedbackLink = () => wrapper.findAllComponents(GlLink).at(0);
|
||||
|
||||
const $router = {
|
||||
push: jest.fn(),
|
||||
};
|
||||
|
||||
function createComponent(lists = null, listTypeToggleEnabled = false) {
|
||||
function createComponent(lists = null) {
|
||||
subscriptionHandler = createMockSubscription();
|
||||
assigneeQueryMock = jest.fn().mockResolvedValue({
|
||||
data: {
|
||||
|
|
@ -106,7 +105,6 @@ describe('Merge requests app component', () => {
|
|||
},
|
||||
provide: {
|
||||
mergeRequestsSearchDashboardPath: '/search',
|
||||
listTypeToggleEnabled,
|
||||
},
|
||||
stubs: {
|
||||
MergeRequestsQuery,
|
||||
|
|
@ -260,22 +258,4 @@ describe('Merge requests app component', () => {
|
|||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('feedback link', () => {
|
||||
it('shows the default feedback link when feature flag is off', async () => {
|
||||
createComponent();
|
||||
await waitForPromises();
|
||||
expect(findFeedbackLink().attributes('href')).toBe(
|
||||
'https://gitlab.com/gitlab-org/gitlab/-/issues/515912',
|
||||
);
|
||||
});
|
||||
|
||||
it('shows the new feedback link when feature flag is on', async () => {
|
||||
createComponent(null, { listTypeToggleEnabled: true });
|
||||
await waitForPromises();
|
||||
expect(findFeedbackLink().attributes('href')).toBe(
|
||||
'https://gitlab.com/gitlab-org/gitlab/-/issues/542823',
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -24,11 +24,7 @@ describe('Merge request dashboard config dropdown component', () => {
|
|||
const findPopover = () => wrapper.findComponent(GlPopover);
|
||||
const { bindInternalEventDocument } = useMockInternalEventsTracking();
|
||||
|
||||
function createComponent({
|
||||
isShowingLabels = false,
|
||||
listTypeToggleEnabled = false,
|
||||
shouldShowCallout = true,
|
||||
} = {}) {
|
||||
function createComponent({ isShowingLabels = false, shouldShowCallout = true } = {}) {
|
||||
setIsShowingLabelsMutationMock = jest.fn();
|
||||
updatePreferencesMutationMock = jest.fn().mockResolvedValue({
|
||||
data: {
|
||||
|
|
@ -70,7 +66,6 @@ describe('Merge request dashboard config dropdown component', () => {
|
|||
|
||||
wrapper = shallowMountExtended(ConfigDropdown, {
|
||||
apolloProvider,
|
||||
provide: { listTypeToggleEnabled },
|
||||
stubs: {
|
||||
UserCalloutDismisser: makeMockUserCalloutDismisser({
|
||||
dismiss: userCalloutDismissSpy,
|
||||
|
|
@ -207,25 +202,23 @@ describe('Merge request dashboard config dropdown component', () => {
|
|||
},
|
||||
);
|
||||
|
||||
describe('when listTypeToggleEnabled is true', () => {
|
||||
it('displays explanation popover when shouldShowCallout is true', () => {
|
||||
createComponent({ listTypeToggleEnabled: true, shouldShowCallout: true });
|
||||
it('displays explanation popover when shouldShowCallout is true', () => {
|
||||
createComponent({ shouldShowCallout: true });
|
||||
|
||||
expect(findPopover().exists()).toBe(true);
|
||||
});
|
||||
expect(findPopover().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('does not display explanation popover when shouldShowCallout is false', () => {
|
||||
createComponent({ listTypeToggleEnabled: true, shouldShowCallout: false });
|
||||
it('does not display explanation popover when shouldShowCallout is false', () => {
|
||||
createComponent({ shouldShowCallout: false });
|
||||
|
||||
expect(findPopover().exists()).toBe(false);
|
||||
});
|
||||
expect(findPopover().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('calls dismiss method createComponent({ listTypeToggleEnabled: true, shouldShowCallout: true });when hiding popover', () => {
|
||||
createComponent({ listTypeToggleEnabled: true, shouldShowCallout: true });
|
||||
it('calls dismiss method when hiding popover', () => {
|
||||
createComponent({ shouldShowCallout: true });
|
||||
|
||||
findPopover().vm.$emit('hidden');
|
||||
findPopover().vm.$emit('hidden');
|
||||
|
||||
expect(userCalloutDismissSpy).toHaveBeenCalled();
|
||||
});
|
||||
expect(userCalloutDismissSpy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ require 'spec_helper'
|
|||
RSpec.describe Banzai::Filter::AutolinkFilter, feature_category: :markdown do
|
||||
include FilterSpecHelper
|
||||
|
||||
let_it_be(:context) { { markdown_engine: Banzai::Filter::MarkdownFilter::CMARK_ENGINE } }
|
||||
let_it_be(:context) { { pipeline: :single_line } }
|
||||
|
||||
let(:link) { 'http://about.gitlab.com/' }
|
||||
let(:quotes) { ['"', "'"] }
|
||||
|
|
|
|||
|
|
@ -83,10 +83,6 @@ RSpec.describe Banzai::Filter::GollumTagsFilter, feature_category: :wiki do
|
|||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'gollum tag parsing' do
|
||||
let_it_be(:context) { { markdown_engine: Banzai::Filter::MarkdownFilter::CMARK_ENGINE } }
|
||||
end
|
||||
|
||||
it_behaves_like 'gollum tag parsing' do
|
||||
let_it_be(:context) { { pipeline: :ascii_doc } }
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,17 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Banzai::Filter::MarkdownEngines::Cmark, feature_category: :markdown do
|
||||
it 'defaults to generating sourcepos' do
|
||||
engine = described_class.new({})
|
||||
|
||||
expect(engine.render('# hi')).to eq %(<h1 data-sourcepos="1:1-1:4">hi</h1>\n)
|
||||
end
|
||||
|
||||
it 'turns off sourcepos' do
|
||||
engine = described_class.new({ no_sourcepos: true })
|
||||
|
||||
expect(engine.render('# hi')).to eq %(<h1>hi</h1>\n)
|
||||
end
|
||||
end
|
||||
|
|
@ -8,8 +8,8 @@ RSpec.describe Banzai::Filter::MarkdownFilter, feature_category: :markdown do
|
|||
|
||||
describe 'markdown engine from context' do
|
||||
it 'finds the correct engine' do
|
||||
expect(described_class.new('foo', { markdown_engine: :cmark }).render_engine)
|
||||
.to eq Banzai::Filter::MarkdownEngines::Cmark
|
||||
expect(described_class.new('foo', { markdown_engine: :glfm_markdown }).render_engine)
|
||||
.to eq Banzai::Filter::MarkdownEngines::GlfmMarkdown
|
||||
end
|
||||
|
||||
it 'defaults to the GLFM_ENGINE' do
|
||||
|
|
|
|||
|
|
@ -72,43 +72,49 @@ module Gitlab
|
|||
items = {
|
||||
'link with extra attribute' => {
|
||||
input: 'link:mylink"onmouseover="alert(1)[Click Here]',
|
||||
output: "<div>\n<p><a href=\"mylink\">Click Here</a></p>\n</div>"
|
||||
output: <<~HTML
|
||||
<div>
|
||||
<p><a href="mylink">Click Here</a></p>
|
||||
</div>
|
||||
HTML
|
||||
},
|
||||
'link with unsafe scheme' => {
|
||||
input: 'link:data://danger[Click Here]',
|
||||
output: "<div>\n<p><a>Click Here</a></p>\n</div>"
|
||||
output: <<~HTML
|
||||
<div>
|
||||
<p><a>Click Here</a></p>
|
||||
</div>
|
||||
HTML
|
||||
},
|
||||
'image with onerror' => {
|
||||
input: 'image:https://localhost.com/image.png[Alt text" onerror="alert(7)]',
|
||||
output: "<div>\n<p><span><a class=\"no-attachment-icon\" href=\"https://localhost.com/image.png\" target=\"_blank\" rel=\"noopener noreferrer\"><img src=\"data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt='Alt text\" onerror=\"alert(7)' decoding=\"async\" class=\"lazy\" data-src=\"https://localhost.com/image.png\"></a></span></p>\n</div>"
|
||||
output: <<~HTML
|
||||
<div>
|
||||
<p><span><a class="no-attachment-icon" href="https://localhost.com/image.png" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt='Alt text" onerror="alert(7)' decoding="async" class="lazy" data-src="https://localhost.com/image.png"></a></span></p>
|
||||
</div>
|
||||
HTML
|
||||
},
|
||||
'fenced code with inline script' => {
|
||||
input: '```mypre"><script>alert(3)</script>',
|
||||
output: <<~HTML
|
||||
<div>
|
||||
<div>
|
||||
<div class="gl-relative markdown-code-block js-markdown-code">
|
||||
<pre data-canonical-lang="mypre" class="code highlight js-syntax-highlight language-plaintext" v-pre="true"><code></code></pre>
|
||||
<copy-code></copy-code><insert-code-snippet></insert-code-snippet>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
HTML
|
||||
}
|
||||
}
|
||||
|
||||
items.each do |name, data|
|
||||
it "does not convert dangerous #{name} into HTML" do
|
||||
expect(render(data[:input], context)).to include(data[:output])
|
||||
expect(render(data[:input], context)).to include(data[:output].strip)
|
||||
end
|
||||
end
|
||||
|
||||
# `stub_feature_flags method` runs AFTER declaration of `items` above.
|
||||
# So the spec in its current implementation won't pass.
|
||||
# Move this test back to the items hash when removing `use_cmark_renderer` feature flag.
|
||||
it "does not convert dangerous fenced code with inline script into HTML" do
|
||||
input = '```mypre"><script>alert(3)</script>'
|
||||
output = <<~HTML
|
||||
<div>
|
||||
<div>
|
||||
<div class="gl-relative markdown-code-block js-markdown-code">
|
||||
<pre data-canonical-lang="mypre" class="code highlight js-syntax-highlight language-plaintext" v-pre="true"><code></code></pre>
|
||||
<copy-code></copy-code><insert-code-snippet></insert-code-snippet>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
HTML
|
||||
|
||||
expect(render(input, context)).to include(output.strip)
|
||||
end
|
||||
|
||||
it 'does not allow locked attributes to be overridden' do
|
||||
input = <<~ADOC
|
||||
{counter:max-include-depth:1234}
|
||||
|
|
|
|||
Loading…
Reference in New Issue