Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2023-07-11 18:10:34 +00:00
parent f4ad4d1900
commit 5842aa3556
85 changed files with 753 additions and 486 deletions

View File

@ -134,7 +134,7 @@ rubocop:
unset CI_SLACK_WEBHOOK_URL
run_timed_command "fail_on_warnings bundle exec rake rubocop:check:graceful"
else
cat "${RSPEC_CHANGED_FILES_PATH}" | ruby -e 'print $stdin.read.split(" ").select { |f| File.exist?(f) }.join(" ")' > "$RUBOCOP_TARGET_FILES"
select_existing_files < "${RSPEC_CHANGED_FILES_PATH}" > "${RUBOCOP_TARGET_FILES}"
# Skip running RuboCop if there's no target files
if [ -s "${RUBOCOP_TARGET_FILES}" ]; then
run_timed_command "fail_on_warnings bundle exec rubocop --parallel --force-exclusion $(cat ${RUBOCOP_TARGET_FILES})"

View File

@ -1,26 +1,19 @@
---
Naming/InclusiveLanguage:
Exclude:
- 'app/controllers/admin/application_settings/appearances_controller.rb'
- 'app/controllers/concerns/requires_whitelisted_monitoring_client.rb'
- 'app/controllers/health_check_controller.rb'
- 'app/controllers/health_controller.rb'
- 'app/controllers/metrics_controller.rb'
- 'app/controllers/concerns/requires_allowlisted_monitoring_client.rb'
- 'app/helpers/application_settings_helper.rb'
- 'app/helpers/blob_helper.rb'
- 'app/helpers/markup_helper.rb'
- 'app/models/application_setting.rb'
- 'app/models/application_setting_implementation.rb'
- 'app/models/concerns/cache_markdown_field.rb'
- 'app/services/application_settings/update_service.rb'
- 'app/services/projects/download_service.rb'
- 'app/uploaders/avatar_uploader.rb'
- 'app/uploaders/content_type_whitelist.rb'
- 'app/uploaders/design_management/design_v432x230_uploader.rb'
- 'app/uploaders/favicon_uploader.rb'
- 'app/uploaders/gitlab_uploader.rb'
- 'app/uploaders/import_export_uploader.rb'
- 'app/validators/cron_validator.rb'
- 'app/validators/qualified_domain_array_validator.rb'
- 'config/initializers/1_settings.rb'
- 'config/initializers/doorkeeper.rb'
@ -28,14 +21,12 @@ Naming/InclusiveLanguage:
- 'ee/app/controllers/projects/push_rules_controller.rb'
- 'ee/lib/arkose/verify_response.rb'
- 'ee/lib/system_check/geo/http_connection_check.rb'
- 'ee/spec/models/dora/lead_time_for_changes_metric_spec.rb'
- 'lib/api/entities/application_setting.rb'
- 'lib/api/settings.rb'
- 'lib/banzai/filter/asset_proxy_filter.rb'
- 'lib/gitlab/asset_proxy.rb'
- 'lib/gitlab/auth/ip_rate_limiter.rb'
- 'lib/gitlab/ci/config/external/file/base.rb'
- 'lib/gitlab/git/hook_env.rb'
- 'lib/gitlab/github_import/markdown/attachment.rb'
- 'lib/gitlab/markdown_cache/active_record/extension.rb'
- 'lib/gitlab/markdown_cache/field_data.rb'
@ -44,9 +35,6 @@ Naming/InclusiveLanguage:
- 'lib/gitlab/sanitizers/svg.rb'
- 'lib/gitlab/sanitizers/svg/whitelist.rb'
- 'lib/system_check/app/git_user_default_ssh_config_check.rb'
- 'rubocop/cop/avoid_return_from_blocks.rb'
- 'rubocop/cop/graphql/id_type.rb'
- 'spec/controllers/concerns/issuable_collections_spec.rb'
- 'spec/controllers/health_check_controller_spec.rb'
- 'spec/controllers/metrics_controller_spec.rb'
- 'spec/helpers/markup_helper_spec.rb'
@ -61,17 +49,7 @@ Naming/InclusiveLanguage:
- 'spec/models/application_setting_spec.rb'
- 'spec/requests/api/settings_spec.rb'
- 'spec/requests/health_controller_spec.rb'
- 'spec/rubocop/cop/avoid_return_from_blocks_spec.rb'
- 'spec/rubocop/cop/graphql/id_type_spec.rb'
- 'spec/services/application_settings/update_service_spec.rb'
- 'spec/services/design_management/generate_image_versions_service_spec.rb'
- 'spec/services/projects/download_service_spec.rb'
- 'spec/support/import_export/export_file_helper.rb'
- 'spec/support/shared_contexts/upload_type_check_shared_context.rb'
- 'spec/support/shared_examples/lib/banzai/filters/sanitization_filter_shared_examples.rb'
- 'spec/support/shared_examples/models/application_setting_shared_examples.rb'
- 'spec/uploaders/avatar_uploader_spec.rb'
- 'spec/uploaders/content_type_whitelist_spec.rb'
- 'spec/uploaders/design_management/design_v432x230_uploader_spec.rb'
- 'spec/uploaders/favicon_uploader_spec.rb'
- 'spec/validators/cron_validator_spec.rb'

View File

@ -227,7 +227,7 @@ export default {
</script>
<template>
<content-editor-provider :content-editor="contentEditor">
<div>
<div class="md-area gl-overflow-hidden">
<editor-state-observer
@docUpdate="notifyChange"
@focus="focus"
@ -238,7 +238,6 @@ export default {
<div
data-testid="content-editor"
data-qa-selector="content_editor_container"
class="md-area gl-border-none! gl-shadow-none!"
:class="{ 'is-focused': focused }"
>
<formatting-toolbar
@ -263,7 +262,7 @@ export default {
<reference-bubble-menu />
</div>
<div
class="gl-display-flex gl-display-flex gl-flex-direction-row gl-justify-content-space-between gl-align-items-center gl-rounded-bottom-left-base gl-rounded-bottom-right-base gl-px-2 gl-mx-2 gl-mb-2 gl-bg-gray-10 gl-text-secondary"
class="gl-display-flex gl-display-flex gl-flex-direction-row gl-justify-content-space-between gl-align-items-center gl-rounded-bottom-left-base gl-rounded-bottom-right-base gl-px-2 gl-border-t gl-border-gray-100 gl-text-secondary"
>
<editor-mode-switcher size="small" value="richText" @input="handleEditorModeChanged" />
<gl-button
@ -274,6 +273,7 @@ export default {
category="tertiary"
size="small"
title="Markdown is supported"
class="gl-px-3!"
/>
</div>
</div>

View File

@ -72,125 +72,123 @@ export default {
};
</script>
<template>
<div class="gl-mx-2 gl-mt-2">
<div
class="gl-w-full gl-display-flex gl-align-items-center gl-flex-wrap gl-bg-gray-50 gl-px-2 gl-rounded-base gl-justify-content-space-between"
data-testid="formatting-toolbar"
>
<div class="gl-py-2 gl-display-flex gl-flex-wrap">
<toolbar-text-style-dropdown
data-testid="text-styles"
@execute="trackToolbarControlExecution"
/>
<toolbar-button
v-if="codeSuggestionsEnabled"
data-testid="code-suggestion"
content-type="codeSuggestion"
icon-name="doc-code"
editor-command="insertCodeSuggestion"
:label="__('Insert suggestion')"
:show-active-state="false"
@execute="trackToolbarControlExecution"
/>
<toolbar-button
data-testid="bold"
content-type="bold"
icon-name="bold"
editor-command="toggleBold"
:label="i18n.bold"
@execute="trackToolbarControlExecution"
/>
<toolbar-button
data-testid="italic"
content-type="italic"
icon-name="italic"
editor-command="toggleItalic"
:label="i18n.italic"
@execute="trackToolbarControlExecution"
/>
<toolbar-button
data-testid="strike"
content-type="strike"
icon-name="strikethrough"
editor-command="toggleStrike"
:label="i18n.strike"
@execute="trackToolbarControlExecution"
/>
<toolbar-button
data-testid="blockquote"
content-type="blockquote"
icon-name="quote"
editor-command="toggleBlockquote"
:label="i18n.quote"
@execute="trackToolbarControlExecution"
/>
<toolbar-button
data-testid="code"
content-type="code"
icon-name="code"
editor-command="toggleCode"
:label="i18n.code"
@execute="trackToolbarControlExecution"
/>
<toolbar-button
data-testid="link"
content-type="link"
icon-name="link"
editor-command="editLink"
:label="i18n.link"
@execute="trackToolbarControlExecution"
/>
<toolbar-button
data-testid="bullet-list"
content-type="bulletList"
icon-name="list-bulleted"
class="gl-display-none gl-sm-display-inline"
editor-command="toggleBulletList"
:label="i18n.bulletList"
@execute="trackToolbarControlExecution"
/>
<toolbar-button
data-testid="ordered-list"
content-type="orderedList"
icon-name="list-numbered"
class="gl-display-none gl-sm-display-inline"
editor-command="toggleOrderedList"
:label="i18n.numberedList"
@execute="trackToolbarControlExecution"
/>
<toolbar-button
data-testid="task-list"
content-type="taskList"
icon-name="list-task"
class="gl-display-none gl-sm-display-inline"
editor-command="toggleTaskList"
:label="i18n.taskList"
@execute="trackToolbarControlExecution"
/>
<toolbar-table-button data-testid="table" @execute="trackToolbarControlExecution" />
<toolbar-attachment-button
v-if="!hideAttachmentButton"
data-testid="attachment"
@execute="trackToolbarControlExecution"
/>
<!-- TODO Add icon and trigger functionality from here -->
<toolbar-button
v-if="supportsQuickActions"
data-testid="quick-actions"
content-type="quickAction"
icon-name="quick-actions"
class="gl-display-none gl-sm-display-inline"
editor-command="insertQuickAction"
:label="__('Add a quick action')"
@execute="trackToolbarControlExecution"
/>
<comment-templates-dropdown
v-if="newCommentTemplatePath"
:new-comment-template-path="newCommentTemplatePath"
@select="insertSavedReply"
/>
<toolbar-more-dropdown data-testid="more" @execute="trackToolbarControlExecution" />
</div>
<div
class="gl-w-full gl-display-flex gl-align-items-center gl-flex-wrap gl-border-b gl-border-gray-100 gl-px-3 gl-rounded-top-base gl-justify-content-space-between"
data-testid="formatting-toolbar"
>
<div class="gl-py-3 gl-display-flex gl-flex-wrap">
<toolbar-text-style-dropdown
data-testid="text-styles"
@execute="trackToolbarControlExecution"
/>
<toolbar-button
v-if="codeSuggestionsEnabled"
data-testid="code-suggestion"
content-type="codeSuggestion"
icon-name="doc-code"
editor-command="insertCodeSuggestion"
:label="__('Insert suggestion')"
:show-active-state="false"
@execute="trackToolbarControlExecution"
/>
<toolbar-button
data-testid="bold"
content-type="bold"
icon-name="bold"
editor-command="toggleBold"
:label="i18n.bold"
@execute="trackToolbarControlExecution"
/>
<toolbar-button
data-testid="italic"
content-type="italic"
icon-name="italic"
editor-command="toggleItalic"
:label="i18n.italic"
@execute="trackToolbarControlExecution"
/>
<toolbar-button
data-testid="strike"
content-type="strike"
icon-name="strikethrough"
editor-command="toggleStrike"
:label="i18n.strike"
@execute="trackToolbarControlExecution"
/>
<toolbar-button
data-testid="blockquote"
content-type="blockquote"
icon-name="quote"
editor-command="toggleBlockquote"
:label="i18n.quote"
@execute="trackToolbarControlExecution"
/>
<toolbar-button
data-testid="code"
content-type="code"
icon-name="code"
editor-command="toggleCode"
:label="i18n.code"
@execute="trackToolbarControlExecution"
/>
<toolbar-button
data-testid="link"
content-type="link"
icon-name="link"
editor-command="editLink"
:label="i18n.link"
@execute="trackToolbarControlExecution"
/>
<toolbar-button
data-testid="bullet-list"
content-type="bulletList"
icon-name="list-bulleted"
class="gl-display-none gl-sm-display-inline"
editor-command="toggleBulletList"
:label="i18n.bulletList"
@execute="trackToolbarControlExecution"
/>
<toolbar-button
data-testid="ordered-list"
content-type="orderedList"
icon-name="list-numbered"
class="gl-display-none gl-sm-display-inline"
editor-command="toggleOrderedList"
:label="i18n.numberedList"
@execute="trackToolbarControlExecution"
/>
<toolbar-button
data-testid="task-list"
content-type="taskList"
icon-name="list-task"
class="gl-display-none gl-sm-display-inline"
editor-command="toggleTaskList"
:label="i18n.taskList"
@execute="trackToolbarControlExecution"
/>
<toolbar-table-button data-testid="table" @execute="trackToolbarControlExecution" />
<toolbar-attachment-button
v-if="!hideAttachmentButton"
data-testid="attachment"
@execute="trackToolbarControlExecution"
/>
<!-- TODO Add icon and trigger functionality from here -->
<toolbar-button
v-if="supportsQuickActions"
data-testid="quick-actions"
content-type="quickAction"
icon-name="quick-actions"
class="gl-display-none gl-sm-display-inline"
editor-command="insertQuickAction"
:label="__('Add a quick action')"
@execute="trackToolbarControlExecution"
/>
<comment-templates-dropdown
v-if="newCommentTemplatePath"
:new-comment-template-path="newCommentTemplatePath"
@select="insertSavedReply"
/>
<toolbar-more-dropdown data-testid="more" @execute="trackToolbarControlExecution" />
</div>
</div>
</template>

View File

@ -74,11 +74,6 @@ import trackInputRulesAndShortcuts from './track_input_rules_and_shortcuts';
const createTiptapEditor = ({ extensions = [], ...options } = {}) =>
new Editor({
extensions: [...extensions],
editorProps: {
attributes: {
class: 'gl-shadow-none!',
},
},
...options,
});

View File

@ -76,10 +76,10 @@ export default {
<h3 id="related-merge-requests" class="gl-new-card-title">
{{ __('Related merge requests') }}
</h3>
<div class="gl-display-inline-flex gl-align-items-center gl-m-0">
<div class="gl-new-card-count">
<template v-if="totalCount">
<gl-icon name="merge-request" class="gl-ml-3 gl-mr-2 gl-text-gray-500" />
<span data-testid="count" class="gl-text-gray-500">{{ totalCount }}</span>
<gl-icon name="merge-request" class="gl-mr-2" />
<span data-testid="count">{{ totalCount }}</span>
</template>
</div>
</div>

View File

@ -229,7 +229,7 @@ export default {
<template #textarea>
<textarea
v-model="timelineText"
class="note-textarea js-gfm-input js-autosize markdown-area"
class="note-textarea note-textarea-rounded-bottom js-gfm-input js-autosize markdown-area gl-bordered"
data-testid="input-note"
dir="auto"
data-supports-quick-actions="false"

View File

@ -66,9 +66,7 @@ export default {
};
</script>
<template>
<div
class="comment-warning-wrapper gl-border-solid gl-border-1 gl-rounded-lg gl-border-gray-100 gl-bg-white gl-overflow-hidden"
>
<div class="comment-warning-wrapper">
<div
v-if="withAlertContainer"
class="error-alert"
@ -76,7 +74,7 @@ export default {
></div>
<noteable-warning
v-if="hasWarning"
class="gl-py-4 gl-border-b-1 gl-border-b-solid gl-border-b-gray-100 gl-rounded-base gl-rounded-bottom-left-none gl-rounded-bottom-right-none"
class="gl-pt-4 gl-pb-5 gl-mb-n3 gl-rounded-lg gl-rounded-bottom-left-none gl-rounded-bottom-right-none"
:is-locked="isLocked"
:is-confidential="isConfidential"
:noteable-type="noteableType"
@ -84,10 +82,20 @@ export default {
:confidential-noteable-docs-path="noteableData.confidential_issues_docs_path"
/>
<slot></slot>
<attachments-warning v-if="showAttachmentWarning" />
<attachments-warning
v-if="showAttachmentWarning"
:class="{
'gl-py-3': !showEmailParticipantsWarning,
'gl-pt-4 gl-pb-3 gl-mt-n3': showEmailParticipantsWarning,
}"
/>
<email-participants-warning
v-if="showEmailParticipantsWarning"
class="gl-border-t-1 gl-border-t-solid gl-border-t-gray-100 gl-rounded-base gl-rounded-top-left-none! gl-rounded-top-right-none!"
class="gl-border-t-1 gl-rounded-lg gl-rounded-top-left-none! gl-rounded-top-right-none!"
:class="{
'gl-pt-4 gl-pb-3 gl-mt-n3': !showAttachmentWarning,
'gl-py-3 gl-mt-1': showAttachmentWarning,
}"
:emails="emailParticipants"
/>
</div>

View File

@ -336,7 +336,7 @@ export default {
<li
v-else-if="canShowReplyActions && showReplies"
data-testid="reply-wrapper"
class="discussion-reply-holder gl-border-t-0! clearfix"
class="discussion-reply-holder gl-border-t-0! gl-pb-5! clearfix"
:class="discussionHolderClass"
>
<discussion-actions

View File

@ -200,13 +200,9 @@ export default {
/>
<slot name="header-text">{{ headerText }}</slot>
</h3>
<div
class="gl-new-card-count js-related-issues-header-issue-count gl-display-inline-flex gl-mx-3 gl-text-gray-500"
>
<span class="gl-display-inline-flex gl-align-items-center">
<gl-icon :name="issuableTypeIcon" class="gl-mr-2 gl-text-gray-500" />
{{ badgeLabel }}
</span>
<div class="gl-new-card-count js-related-issues-header-issue-count">
<gl-icon :name="issuableTypeIcon" class="gl-mr-2" />
{{ badgeLabel }}
</div>
</div>
<slot name="header-actions"></slot>
@ -220,7 +216,7 @@ export default {
>
<slot name="add-button-text">{{ __('Add') }}</slot>
</gl-button>
<div class="gl-pl-3 gl-ml-3 gl-border-l-1 gl-border-l-solid gl-border-l-gray-100">
<div class="gl-new-card-toggle">
<gl-button
category="tertiary"
size="small"
@ -282,7 +278,7 @@ export default {
@saveReorder="$emit('saveReorder', $event)"
/>
</template>
<div v-if="!shouldShowTokenBody && !isFormVisible" data-testid="related-items-empty">
<div v-if="!shouldShowTokenBody && !isFormVisible">
<p class="gl-new-card-empty">
{{ emptyStateMessage }}
<gl-link

View File

@ -121,6 +121,7 @@ export default {
:default-toggle-text="$options.i18n.toggleText"
:fetch-items="fetchGroups"
:fetch-initial-selection-text="fetchGroupName"
v-on="$listeners"
>
<template #error>
<gl-alert v-if="errorMessage" class="gl-mb-3" variant="danger" @dismiss="dismissError">{{

View File

@ -166,6 +166,7 @@ export default {
:fetch-initial-selection-text="fetchProjectName"
:block="block"
clearable
v-on="$listeners"
>
<template v-if="hasHtmlLabel" #label>
<span v-safe-html="label"></span>

View File

@ -27,7 +27,7 @@ export default {
<template>
<div class="content-editor-switcher gl-display-inline-flex gl-align-items-center">
<gl-button
class="btn btn-default btn-sm gl-button btn-default-tertiary"
class="btn btn-default btn-sm gl-button btn-default-tertiary gl-font-sm! gl-text-secondary! gl-px-4!"
data-qa-selector="editing_mode_switcher"
@click="$emit('input')"
>{{ text }}</gl-button

View File

@ -355,10 +355,7 @@ export default {
<template>
<div
ref="gl-form"
:class="{
'gl-border-none! gl-shadow-none!': removeBorder,
}"
class="js-vue-markdown-field md-area position-relative gfm-form"
class="js-vue-markdown-field md-area position-relative gfm-form gl-overflow-hidden"
:data-uploads-path="uploadsPath"
>
<markdown-header

View File

@ -257,11 +257,11 @@ export default {
</script>
<template>
<div class="md-header gl-bg-gray-50 gl-px-2 gl-rounded-base gl-mx-2 gl-mt-2">
<div class="md-header gl-border-b gl-border-gray-100 gl-px-3">
<div class="gl-display-flex gl-align-items-center gl-flex-wrap">
<div
data-testid="md-header-toolbar"
class="md-header-toolbar gl-display-flex gl-py-2 gl-flex-wrap gl-row-gap-3"
class="md-header-toolbar gl-display-flex gl-py-3 gl-flex-wrap gl-row-gap-3"
>
<gl-button
v-if="enablePreview"

View File

@ -226,7 +226,7 @@ export default {
};
</script>
<template>
<div class="md-area gl-px-0! gl-overflow-hidden">
<div class="gl-px-0!">
<local-storage-sync
:value="editingMode"
as-string

View File

@ -50,11 +50,11 @@ export default {
<template>
<div
v-if="showCommentToolBar"
class="comment-toolbar gl-display-flex gl-flex-direction-row gl-mx-2 gl-mb-2 gl-px-2 gl-rounded-bottom-left-base gl-rounded-bottom-right-base"
class="comment-toolbar gl-display-flex gl-flex-direction-row gl-px-2 gl-rounded-bottom-left-base gl-rounded-bottom-right-base"
:class="
showContentEditorSwitcher
? 'gl-bg-gray-10 gl-justify-content-space-between'
: 'gl-justify-content-end'
? 'gl-justify-content-space-between gl-align-items-center gl-border-t gl-border-gray-100'
: 'gl-justify-content-end gl-my-2'
"
>
<editor-mode-switcher
@ -63,21 +63,8 @@ export default {
value="markdown"
@input="handleEditorModeChanged"
/>
<div>
<div class="toolbar-text gl-font-sm">
<template v-if="markdownDocsPath">
<gl-button
v-gl-tooltip
icon="markdown-mark"
:href="markdownDocsPath"
target="_blank"
category="tertiary"
size="small"
title="Markdown is supported"
/>
</template>
</div>
<span v-if="canAttachFile" class="uploading-container gl-font-sm gl-line-height-32">
<div class="gl-display-flex">
<div v-if="canAttachFile" class="uploading-container gl-font-sm gl-line-height-32 gl-mr-3">
<span class="uploading-progress-container hide">
<gl-icon name="paperclip" />
<span class="attaching-file-message"></span>
@ -125,7 +112,18 @@ export default {
>
{{ __('Cancel') }}
</gl-button>
</span>
</div>
<gl-button
v-if="markdownDocsPath"
v-gl-tooltip
icon="markdown-mark"
:href="markdownDocsPath"
target="_blank"
category="tertiary"
size="small"
title="Markdown is supported"
class="gl-px-3!"
/>
</div>
</div>
</template>

View File

@ -205,10 +205,7 @@ export default {
>
<template #header>{{ $options.i18n.title }}</template>
<template #header-suffix>
<span
class="gl-display-inline-flex gl-align-items-center gl-line-height-24 gl-ml-3 gl-font-weight-bold gl-text-gray-500"
data-testid="children-count"
>
<span class="gl-new-card-count" data-testid="children-count">
<gl-icon :name="$options.WIDGET_TYPE_TASK_ICON" class="gl-mr-2" />
{{ childrenCountLabel }}
</span>

View File

@ -6,11 +6,16 @@
max-height: 55vh;
position: static;
overflow-y: auto;
transition: box-shadow ease-in-out 0.15s;
::selection {
background-color: transparent;
}
&:focus {
@include gl-focus($inset: true);
}
&:not(.ProseMirror-hideselection) .content-editor-selection,
a.ProseMirror-selectednode,
span.ProseMirror-selectednode {

View File

@ -91,7 +91,7 @@
}
.md-preview-holder {
min-height: 176px;
min-height: 173px;
padding: 10px 0;
overflow-x: auto;
}
@ -106,6 +106,7 @@
box-shadow: none;
width: 100%;
resize: none !important;
transition: box-shadow $gl-transition-duration-medium ease;
}
.md-suggestion-diff {

View File

@ -7,8 +7,7 @@
@include gl-rounded-base;
&-header {
@include gl-pl-5;
@include gl-pr-4;
@include gl-px-5;
@include gl-py-4;
@include gl-display-flex;
@include gl-justify-content-space-between;
@ -42,6 +41,8 @@
@include gl-font-base;
@include gl-font-weight-bold;
@include gl-text-gray-500;
@include gl-display-inline-flex;
@include gl-align-items-center;
}
&-description {
@ -53,6 +54,7 @@
&-toggle {
@include gl-pl-3;
@include gl-ml-3;
@include gl-mr-n2;
@include gl-border-l-1;
@include gl-border-l-solid;
@include gl-border-l-gray-100;

View File

@ -48,7 +48,7 @@
.common-note-form {
.md-area {
border: 1px solid $border-color;
border: 1px solid $gray-400;
border-radius: $border-radius-large;
transition: border-color ease-in-out 0.15s,
box-shadow ease-in-out 0.15s;
@ -65,19 +65,34 @@
}
}
// Disable inner focus
&:hover,
&:focus-within {
@include gl-shadow-md;
}
&:hover {
border: 1px solid $gray-500;
}
&:focus-within {
border: 1px solid $gray-900;
}
// Add focus
textarea:focus {
@include gl-shadow-none;
@include gl-focus($inset: true);
}
.note-textarea-rounded-bottom {
border-bottom-left-radius: calc(#{$border-radius-large} - 1px);
border-bottom-right-radius: calc(#{$border-radius-large} - 1px);
}
// Disable inner focus on fullscreen
.zen-backdrop.fullscreen textarea:focus {
box-shadow: none;
}
}
.comment-warning-wrapper:focus-within {
@include gl-focus;
}
}
.md-area:focus-within {
@include gl-focus;
}
.md-header {
@ -217,6 +232,7 @@ table {
.md-area {
background-color: $white;
@include gl-rounded-base;
}
}
@ -309,13 +325,19 @@ table {
resize: none;
padding: $gl-padding-8 $gl-padding-12;
line-height: 1;
border: 1px solid $border-color;
border: 1px solid $gray-200;
background-color: $white;
overflow: hidden;
transition: border-color ease-in-out 0.15s,
box-shadow ease-in-out 0.15s;
@include media-breakpoint-down(xs) {
margin-bottom: $gl-padding-8;
}
&:hover {
border: 1px solid $gray-500;
}
}
}
@ -436,9 +458,4 @@ table {
.comment-warning-wrapper {
transition: border-color ease-in-out 0.15s,
box-shadow ease-in-out 0.15s;
.md-area {
border: 0;
box-shadow: none;
}
}

View File

@ -69,7 +69,7 @@ class Admin::ApplicationSettings::AppearancesController < Admin::ApplicationCont
@appearance = Appearance.current || Appearance.new
end
# Only allow a trusted parameter "white list" through.
# Only allow a trusted parameter "allow list" through.
def appearance_params
params.require(:appearance).permit(allowed_appearance_params)
end

View File

@ -5,26 +5,23 @@ module Observability
extend ActiveSupport::Concern
included do
content_security_policy_with_context do |p|
current_group = if defined?(group)
group
else
defined?(project) ? project&.group : nil
end
next if p.directives.blank? || !Feature.enabled?(:observability_group_tab, current_group)
content_security_policy do |p|
next if p.directives.blank?
default_frame_src = p.directives['frame-src'] || p.directives['default-src']
# When ObservabilityUI is not authenticated, it needs to be able
# to redirect to the GL sign-in page, hence '/users/sign_in' and '/oauth/authorize'
# When Gitlab Observability Backend is not authenticated, it needs to be able
# to redirect to the GitLab sign-in page, hence '/users/sign_in' and '/oauth/authorize'
frame_src_values = Array.wrap(default_frame_src) | [
Gitlab::Observability.observability_url,
Gitlab::Utils.append_path(Gitlab.config.gitlab.url, '/users/sign_in'),
Gitlab::Utils.append_path(Gitlab.config.gitlab.url, '/oauth/authorize')
]
p.frame_src(*frame_src_values)
default_connect_src = p.directives['connect-src'] || p.directives['default-src']
connect_src_values =
Array.wrap(default_connect_src) | [Gitlab::Observability.observability_url]
p.connect_src(*connect_src_values)
end
end
end

View File

@ -1,28 +1,28 @@
# frozen_string_literal: true
module RequiresWhitelistedMonitoringClient
module RequiresAllowlistedMonitoringClient
extend ActiveSupport::Concern
included do
before_action :validate_ip_whitelisted_or_valid_token!
before_action :validate_ip_allowlisted_or_valid_token!
end
private
def validate_ip_whitelisted_or_valid_token!
render_404 unless client_ip_whitelisted? || valid_token?
def validate_ip_allowlisted_or_valid_token!
render_404 unless client_ip_allowlisted? || valid_token?
end
def client_ip_whitelisted?
def client_ip_allowlisted?
# Always allow developers to access http://localhost:3000/-/metrics for
# debugging purposes
return true if Rails.env.development? && request.local?
ip_whitelist.any? { |e| e.include?(Gitlab::RequestContext.instance.client_ip) }
ip_allowlist.any? { |e| e.include?(Gitlab::RequestContext.instance.client_ip) }
end
def ip_whitelist
@ip_whitelist ||= Settings.monitoring.ip_whitelist.map { |ip| IPAddr.new(ip) }
def ip_allowlist
@ip_allowlist ||= Settings.monitoring.ip_whitelist.map { |ip| IPAddr.new(ip) }
end
def valid_token?

View File

@ -1,5 +1,5 @@
# frozen_string_literal: true
class HealthCheckController < HealthCheck::HealthCheckController
include RequiresWhitelistedMonitoringClient
include RequiresAllowlistedMonitoringClient
end

View File

@ -3,7 +3,7 @@
# rubocop:disable Rails/ApplicationController
class HealthController < ActionController::Base
protect_from_forgery with: :exception, prepend: true
include RequiresWhitelistedMonitoringClient
include RequiresAllowlistedMonitoringClient
CHECKS = [
Gitlab::HealthChecks::MasterCheck

View File

@ -2,7 +2,7 @@
# rubocop:disable Rails/ApplicationController
class MetricsController < ActionController::Base
include RequiresWhitelistedMonitoringClient
include RequiresAllowlistedMonitoringClient
protect_from_forgery with: :exception, prepend: true

View File

@ -0,0 +1,22 @@
# frozen_string_literal: true
module Projects
class TracingController < Projects::ApplicationController
include ::Observability::ContentSecurityPolicy
feature_category :tracing
before_action :check_tracing_enabled
def index
# TODO frontend changes coming separately https://gitlab.com/gitlab-org/gitlab/-/merge_requests/125014
render html: helpers.tag.strong('Tracing')
end
private
def check_tracing_enabled
render_404 unless Gitlab::Observability.tracing_enabled?(project)
end
end
end

View File

@ -118,8 +118,8 @@ module BlobHelper
"#{blob_raw_path.rpartition('/').first}/"
end
# SVGs can contain malicious JavaScript; only include whitelisted
# elements and attributes. Note that this whitelist is by no means complete
# SVGs can contain malicious JavaScript; only include allowlisted
# elements and attributes. Note that this allowlist is by no means complete
# and may omit some elements.
def sanitize_svg_data(data)
Gitlab::Sanitizers::SVG.clean(data)

View File

@ -2,7 +2,7 @@
module Projects
class DownloadService < BaseService
WHITELIST = [
ALLOWLIST = [
/^[^.]+\.fogbugz.com$/
].freeze
@ -33,7 +33,7 @@ module Projects
def valid_domain?(url)
host = URI.parse(url).host
WHITELIST.any? { |entry| entry === host }
ALLOWLIST.any? { |entry| entry === host }
end
end
end

View File

@ -1,16 +1,16 @@
# frozen_string_literal: true
class CronValidator < ActiveModel::EachValidator
ATTRIBUTE_WHITELIST = %i[cron freeze_start freeze_end].freeze
ATTRIBUTE_ALLOWLIST = %i[cron freeze_start freeze_end].freeze
NonWhitelistedAttributeError = Class.new(StandardError)
NonAllowlistedAttributeError = Class.new(StandardError)
def validate_each(record, attribute, value)
if ATTRIBUTE_WHITELIST.include?(attribute)
if ATTRIBUTE_ALLOWLIST.include?(attribute)
cron_parser = Gitlab::Ci::CronParser.new(record.public_send(attribute), record.cron_timezone) # rubocop:disable GitlabSecurity/PublicSend
record.errors.add(attribute, " is invalid syntax") unless cron_parser.cron_valid?
else
raise NonWhitelistedAttributeError, "Non-whitelisted attribute"
raise NonAllowlistedAttributeError, "Non-allowlisted attribute"
end
end
end

View File

@ -9,9 +9,9 @@
= _('Only project members can comment.')
.md-area.position-relative
.md-header.gl-bg-gray-50.gl-px-2.gl-rounded-base.gl-mx-2.gl-mt-2
.md-header.gl-px-3.gl-rounded-top-base.gl-border-b.gl-border-gray-100
.gl-display-flex.gl-align-items-center.gl-flex-wrap.gl-justify-content-space-between
.md-header-toolbar.gl-display-flex.gl-py-2.gl-flex-wrap.gl-row-gap-3
.md-header-toolbar.gl-display-flex.gl-py-3.gl-flex-wrap.gl-row-gap-3
= render Pajamas::ButtonComponent.new(category: :tertiary, size: :small, button_options: { class: 'js-md-preview-button', value: 'preview' }) do
= _('Preview')
= render 'shared/blob/markdown_buttons', supports_quick_actions: supports_quick_actions

View File

@ -1,7 +1,7 @@
- supports_file_upload = local_assigns.fetch(:supports_file_upload, true)
.comment-toolbar.gl-mx-2.gl-mb-2.gl-px-2.gl-display-flex.gl-justify-content-end.gl-rounded-bottom-left-base.gl-rounded-bottom-right-base.clearfix
.toolbar-text
= render Pajamas::ButtonComponent.new(category: :tertiary, icon: 'markdown-mark', size: :small, href: help_page_path('user/markdown'), target: '_blank')
.comment-toolbar.gl-px-2.gl-display-flex.gl-justify-content-end.gl-rounded-bottom-left-base.gl-rounded-bottom-right-base.clearfix
.content-editor-switcher.gl-display-inline-flex.gl-align-items-center
= render Pajamas::ButtonComponent.new(category: :tertiary, icon: 'markdown-mark', size: :small, href: help_page_path('user/markdown'), target: '_blank', button_options: { class: 'gl-px-3!' })
- if supports_file_upload
%span.uploading-container.gl-line-height-32.gl-font-sm
%span.uploading-progress-container.hide

View File

@ -0,0 +1,8 @@
---
name: observability_tracing
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/124966
rollout_issue_url: https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/2252
milestone: '16.2'
type: development
group: group::observability
default_enabled: false

View File

@ -0,0 +1,8 @@
---
name: packages_dependency_proxy_maven
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123491
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/415218
milestone: '16.2'
type: development
group: group::package registry
default_enabled: false

View File

@ -404,6 +404,8 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
end
end
resources :tracing, only: [:index], controller: :tracing
namespace :design_management do
namespace :designs, path: 'designs/:design_id(/:sha)', constraints: -> (params) { params[:sha].nil? || Gitlab::Git.commit_id?(params[:sha]) } do
resource :raw_image, only: :show

View File

@ -3,7 +3,7 @@ table_name: dependency_proxy_packages_settings
classes:
- DependencyProxy::Packages::Setting
feature_categories:
- dependency_proxy
- package_registry
description: Settings for the dependency proxy for packages.
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/120894
milestone: '16.1'

View File

@ -46,6 +46,7 @@ Here's a list of where we're using this right now, and should try to move away
from using `$FORCE_GITLAB_CI`.
- [JiHu validation pipeline](https://about.gitlab.com/handbook/ceo/chief-of-staff-team/jihu-support/jihu-validation-pipelines.html)
- [Gitaly downstream GitLab pipeline](https://gitlab.com/gitlab-org/gitaly/-/issues/4615)
## Default image

View File

@ -103,6 +103,11 @@ To view a list of seats being used:
1. Select **Settings > Usage Quotas**.
1. On the **Seats** tab, view usage information.
For each user, a list shows groups and projects where the user is a direct member.
- **Group invite** indicates the user is a member of a [group shared with a group](../../user/group/manage.md#share-a-group-with-another-group).
- **Project invite** indicates the user is a member of a [group shared with a project](../../user/project/members/share_project_with_groups.md#share-a-project-with-a-group).
The data in seat usage listing, **Seats in use**, and **Seats in subscription** are updated live.
The counts for **Max seats used** and **Seats owed** are updated once per day.

View File

@ -312,6 +312,8 @@ and [Helm Chart deployments](https://docs.gitlab.com/charts/). They come with ap
- Geo: Some project imports do not initialize wiki repositories on project creation. Since the migration of project wikis to SSF, [missing wiki repositories are being incorrectly flagged as failing verification](https://gitlab.com/gitlab-org/gitlab/-/issues/409704). This is not a result of an actual replication/verification failure but an invalid internal state for these missing repositories inside Geo and results in errors in the logs and the verification progress reporting a failed state for these wiki repositories. If you have not imported projects you are not impacted by this issue.
- Impacted versions: GitLab versions 15.11.x, 16.0.x, and 16.1.0 - 16.1.2.
- Versions containing fix: GitLab 16.1.3 and later.
- Starting with 16.0, GitLab self-managed installations now have two database connections by default, instead of one. This change doubles the number of PostgreSQL connections. It makes self-managed versions of GitLab behave similarly to GitLab.com, and is a step toward enabling a separate database for CI features for self-managed versions of GitLab. Before upgrading to 16.0, determine if you need to [increase max connections for PostgreSQL](https://docs.gitlab.com/omnibus/settings/database.html#configuring-multiple-database-connections).
- This change applies to installation methods with Linux packages (Omnibus GitLab), GitLab Helm chart, GitLab Operator, GitLab Docker images, and installation from source.
### 15.11.1

View File

@ -114,11 +114,13 @@ Admin Mode times out after six hours, and you cannot change this timeout limit.
The following access methods are **not** protected by Admin Mode:
- Git client access (SSH using public keys or HTTPS using Personal Access Tokens).
- API access using a Personal Access Token.
In other words, administrators who are otherwise limited by Admin Mode can still use
Git clients, and access RESTful API endpoints as administrators, without additional
authentication steps.
Git clients without additional authentication steps.
To use the GitLab REST- or GraphQL API, administrators must [create a personal access token](../../profile/personal_access_tokens.md#create-a-personal-access-token) with the [`admin_mode` scope](../../profile/personal_access_tokens.md#personal-access-token-scopes).
If an administrator with a personal access token with the `admin_mode` scope loses their administrator access, that user cannot access the API as an administrator even though they still have the token with the `admin_mode` scope.
We may address these limitations in the future. For more information see the following epic:
[Admin Mode for GitLab Administrators](https://gitlab.com/groups/gitlab-org/-/epics/2158).

View File

@ -635,7 +635,6 @@ The following variables allow configuration of global dependency scanning settin
| `DS_IMAGE_SUFFIX` | Suffix added to the image name. ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/354796) in GitLab 14.10.) Automatically set to `"-fips"` when FIPS mode is enabled. ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/357922) in GitLab 15.0.) |
| `DS_MAX_DEPTH` | Defines how many directory levels deep that the analyzer should search for supported files to scan. A value of `-1` scans all directories regardless of depth. Default: `2`. |
| `SECURE_ANALYZERS_PREFIX` | Override the name of the Docker registry providing the official default images (proxy). |
| `SECURE_LOG_LEVEL` | Set the minimum logging level. Messages of this logging level or higher are output. From highest to lowest severity, the logging levels are: `fatal`, `error`, `warn`, `info` (default), `debug`. |
#### Configuring specific analyzers used by dependency scanning
@ -1136,12 +1135,10 @@ version number).
## Troubleshooting
### Increase log verbosity
### Debug-level logging
When a [job log](../../../ci/jobs/index.md#expand-and-collapse-job-log-sections)
doesn't contain enough information about a dependency-scanning failure,
[set `SECURE_LOG_LEVEL` to `debug`](#configuring-dependency-scanning)
and check the resulting, more verbose log.
Debug-level logging can help when troubleshooting. For details, see
[debug-level logging](../index.md#debug-level-logging).
### Working around missing support for certain languages or package managers

View File

@ -270,15 +270,10 @@ pipelines tab on merge requests by [setting `artifacts: paths`](../../../ci/yaml
## Troubleshooting
### IaC debug logging
### Debug-level logging
To help troubleshoot IaC jobs, you can increase the [Secure scanner log verbosity](../sast/index.md#logging-level)
by using a global CI/CD variable set to `debug`:
```yaml
variables:
SECURE_LOG_LEVEL: "debug"
```
Debug-level logging can help when troubleshooting. For details, see
[debug-level logging](../index.md#debug-level-logging).
### IaC Scanning findings show as `No longer detected` unexpectedly

View File

@ -536,24 +536,48 @@ Feedback is welcome on our vision for [unifying the user experience for these tw
## Troubleshooting
<!-- NOTE: The below subsection(`### Secure job failing with exit code 1`) documentation URL is referred in the [/gitlab-org/security-products/analyzers/command](https://gitlab.com/gitlab-org/security-products/analyzers/command/-/blob/main/command.go#L19) repository. If this section/subsection changes, please ensure to update the corresponding URL in the mentioned repository.
-->
### Logging level
### Secure job failing with exit code 1
The verbosity of logs output by GitLab analyzers is determined by the `SECURE_LOG_LEVEL` environment
variable. Messages of this logging level or higher are output.
From highest to lowest severity, the logging levels are:
- `fatal`
- `error`
- `warn`
- `info` (default)
- `debug`
#### Debug-level logging
WARNING:
Debug logging can be a serious security risk. The output may contain the content of
environment variables and other secrets available to the job. The output is uploaded
to the GitLab server and visible in job logs.
to the GitLab server and is visible in job logs.
If a Secure job is failing and it's unclear why, add `SECURE_LOG_LEVEL: "debug"` as a global CI/CD variable for
more verbose output that is helpful for troubleshooting.
To enable debug-level logging, add the following to your `.gitlab-ci.yml` file:
```yaml
variables:
SECURE_LOG_LEVEL: "debug"
```
This indicates to all GitLab analyzers that they are to output **all** messages. For more details,
see [logging level](#logging-level).
<!-- NOTE: The below subsection(`### Secure job failing with exit code 1`) documentation URL is referred in the [/gitlab-org/security-products/analyzers/command](https://gitlab.com/gitlab-org/security-products/analyzers/command/-/blob/main/command.go#L19) repository. If this section/subsection changes, please ensure to update the corresponding URL in the mentioned repository.
-->
### Secure job failing with exit code 1
If a Secure job is failing and it's unclear why:
1. Enable [debug-level logging](#debug-level-logging).
1. Run the job.
1. Examine the job's output.
1. Set the logging level to `info` (default).
### Outdated security reports
When a security report generated for a merge request becomes outdated, the merge request shows a

View File

@ -519,21 +519,6 @@ variables:
SEARCH_MAX_DEPTH: 10
```
#### Logging level
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/10880) in GitLab 13.1.
To control the verbosity of logs, set the `SECURE_LOG_LEVEL` environment variable. Messages of this
logging level or higher are output.
From highest to lowest severity, the logging levels are:
- `fatal`
- `error`
- `warn`
- `info` (default)
- `debug`
#### Custom Certificate Authority
To trust a custom Certificate Authority, set the `ADDITIONAL_CA_CERT_BUNDLE` variable to the bundle
@ -772,14 +757,10 @@ By default SAST analyzers are supported in GitLab instances hosted on SELinux. A
## Troubleshooting
### SAST debug logging
### Debug-level logging
Increase the [Secure scanner log verbosity](#logging-level) to `debug` in a global CI variable to help troubleshoot SAST jobs.
```yaml
variables:
SECURE_LOG_LEVEL: "debug"
```
Debug-level logging can help when troubleshooting. For details, see
[debug-level logging](../index.md#debug-level-logging).
### Pipeline errors related to changes in the GitLab-managed CI/CD template

View File

@ -629,21 +629,10 @@ This feature is separate from Secret Detection scanning, which checks your Git r
## Troubleshooting
### Set the logging level
### Debug-level logging
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/10880) in GitLab 13.1.
Set the logging level to `debug` when you need diagnostic information in a Secret Detection job log.
WARNING:
Debug logging can be a serious security risk. The output may contain the content of environment
variables and other secrets available to the job. The output is uploaded to the GitLab server and
visible in job logs.
1. In the `.gitlab-ci.yml` file, set the `SECURE_LOG_LEVEL` CI/CD variable to `debug`.
1. Run the Secret Detection job.
1. Analyze the content of the Secret Detection job.
1. In the `.gitlab-ci.yml` file, set the `SECURE_LOG_LEVEL` CI/CD variable to `info` (default).
Debug-level logging can help when troubleshooting. For details, see
[debug-level logging](../index.md#debug-level-logging).
### Warning: `gl-secret-detection-report.json: no matching files`
@ -661,8 +650,8 @@ For example, you could have a pipeline triggered from a merge request containing
clone is not deep enough to contain all of the relevant commits. To verify the current value, see
[pipeline configuration](../../../ci/pipelines/settings.md#limit-the-number-of-changes-fetched-during-clone).
To confirm this as the cause of the error, set the [logging level](#set-the-logging-level) to
`debug`, then rerun the pipeline. The logs should look similar to the following example. The text
To confirm this as the cause of the error, enable [debug-level logging](../index.md#debug-level-logging),
then rerun the pipeline. The logs should look similar to the following example. The text
"object not found" is a symptom of this error.
```plaintext

View File

@ -0,0 +1,28 @@
---
stage: Manage
group: Foundations
info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments"
type: reference
---
# Command palette **(FREE)**
> Introduced in GitLab 16.2 [with a flag](../../administration/feature_flags.md) named `command_palette`. Disabled by default.
You can use command palette to narrow down the scope of your search or to
find an object more quickly.
FLAG:
On self-managed GitLab, by default this feature is not available. To make it available, ask an administrator to enable the feature flag named `command_palette`. On GitLab.com, this feature is not available.
## Open the command palette
To open the command palette:
1. On the left sidebar, at the top, select **Search GitLab** (**{search}**).
1. Type one of the special characters:
- <kbd>></kbd> - Use to create a new object or to find a menu item.
- <kbd>@</kbd> - Search for user.
- <kbd>:</kbd> - Search for project.
- <kbd>/</kbd> - Search for project files in the default repository branch.

View File

@ -0,0 +1,22 @@
# frozen_string_literal: true
module API
module Helpers
module Packages
module Maven
extend Grape::API::Helpers
params :path_and_file_name do
requires :path,
type: String,
desc: 'Package path',
documentation: { example: 'foo/bar/mypkg/1.0-SNAPSHOT' }
requires :file_name,
type: String,
desc: 'Package file name',
documentation: { example: 'mypkg-1.0-SNAPSHOT.jar' }
end
end
end
end
end

View File

@ -23,14 +23,10 @@ module API
helpers ::API::Helpers::PackagesHelpers
helpers ::API::Helpers::Packages::DependencyProxyHelpers
helpers ::API::Helpers::Packages::Maven
helpers ::API::Helpers::Packages::Maven::BasicAuthHelpers
helpers do
params :path_and_file_name do
requires :path, type: String, desc: 'Package path', documentation: { example: 'foo/bar/mypkg/1.0-SNAPSHOT' }
requires :file_name, type: String, desc: 'Package file name', documentation: { example: 'mypkg-1.0-SNAPSHOT.jar' }
end
def path_exists?(path)
return false if path.blank?

View File

@ -14,7 +14,7 @@ module Gitlab
#
# This class is thread-safe via RequestStore.
class HookEnv
WHITELISTED_VARIABLES = %w[
ALLOWLISTED_VARIABLES = %w[
GIT_OBJECT_DIRECTORY_RELATIVE
GIT_ALTERNATE_OBJECT_DIRECTORIES_RELATIVE
].freeze
@ -25,7 +25,7 @@ module Gitlab
raise "missing gl_repository" if gl_repository.blank?
Gitlab::SafeRequestStore[:gitlab_git_env] ||= {}
Gitlab::SafeRequestStore[:gitlab_git_env][gl_repository] = whitelist_git_env(env)
Gitlab::SafeRequestStore[:gitlab_git_env][gl_repository] = allowlist_git_env(env)
end
def self.all(gl_repository)
@ -46,8 +46,8 @@ module Gitlab
env
end
def self.whitelist_git_env(env)
env.select { |key, _| WHITELISTED_VARIABLES.include?(key.to_s) }.with_indifferent_access
def self.allowlist_git_env(env)
env.select { |key, _| ALLOWLISTED_VARIABLES.include?(key.to_s) }.with_indifferent_access
end
end
end

View File

@ -23,7 +23,13 @@ module Gitlab
'https://observe.gitlab.com'
end
# Returns true if the Observability feature flag is enabled
def oauth_url
"#{Gitlab::Observability.observability_url}/v1/auth/start"
end
# Returns true if the GitLab Observability UI (GOUI) feature flag is enabled
#
# @deprecated
#
def enabled?(group = nil)
return Feature.enabled?(:observability_group_tab, group) if group
@ -31,6 +37,11 @@ module Gitlab
Feature.enabled?(:observability_group_tab)
end
# Returns true if Tracing UI is enabled
def tracing_enabled?(project)
Feature.enabled?(:observability_tracing, project)
end
# Returns the embeddable Observability URL of a given URL
#
# - Validates the URL

View File

@ -8,6 +8,7 @@ module Sidebars
def configure_menu_items
return false unless feature_enabled?
add_item(tracing_menu_item)
add_item(error_tracking_menu_item)
add_item(alert_management_menu_item)
add_item(incidents_menu_item)
@ -62,6 +63,20 @@ module Sidebars
)
end
def tracing_menu_item
unless Gitlab::Observability.tracing_enabled?(context.project)
return ::Sidebars::NilMenuItem.new(item_id: :tracing)
end
::Sidebars::MenuItem.new(
title: _('Tracing'),
link: project_tracing_index_path(context.project),
super_sidebar_parent: ::Sidebars::Projects::SuperSidebarMenus::MonitorMenu,
active_routes: { controller: :tracing },
item_id: :tracing
)
end
def alert_management_menu_item
unless can?(context.current_user, :read_alert_management_alert, context.project)
return ::Sidebars::NilMenuItem.new(item_id: :alert_management)

View File

@ -17,6 +17,7 @@ module Sidebars
override :configure_menu_items
def configure_menu_items
[
:tracing,
:error_tracking,
:alert_management,
:incidents,

View File

@ -48319,6 +48319,9 @@ msgstr ""
msgid "TotalRefCountIndicator|1000+"
msgstr ""
msgid "Tracing"
msgstr ""
msgid "Track groups of issues that share a theme, across projects and milestones"
msgstr ""

View File

@ -23,7 +23,7 @@ module RuboCop
class AvoidReturnFromBlocks < RuboCop::Cop::Base
MSG = 'Do not return from a block, use next or break instead.'
DEF_METHODS = %i[define_method lambda].freeze
WHITELISTED_METHODS = %i[each each_filename times loop].freeze
ALLOWLISTED_METHODS = %i[each each_filename times loop].freeze
def on_block(node)
block_body = node.body
@ -32,7 +32,7 @@ module RuboCop
return unless top_block?(node)
block_body.each_node(:return) do |return_node|
next if parent_blocks(node, return_node).all? { |block_node| whitelisted?(block_node) }
next if parent_blocks(node, return_node).all? { |block_node| allowlisted?(block_node) }
add_offense(return_node)
end
@ -69,8 +69,8 @@ module RuboCop
(node.type == :block && DEF_METHODS.include?(node.method_name))
end
def whitelisted?(block_node)
WHITELISTED_METHODS.include?(block_node.method_name)
def allowlisted?(block_node)
ALLOWLISTED_METHODS.include?(block_node.method_name)
end
end
end

View File

@ -6,7 +6,7 @@ module RuboCop
class IDType < RuboCop::Cop::Base
MSG = 'Do not use GraphQL::Types::ID, use a specific GlobalIDType instead'
WHITELISTED_ARGUMENTS = %i[iid full_path project_path group_path target_project_path namespace_path].freeze
ALLOWLISTED_ARGUMENTS = %i[iid full_path project_path group_path target_project_path namespace_path].freeze
def_node_search :graphql_id_type?, <<~PATTERN
(send nil? :argument (_ #does_not_match?) (const (const (const nil? :GraphQL) :Types) :ID) ...)
@ -21,7 +21,7 @@ module RuboCop
private
def does_not_match?(arg)
!WHITELISTED_ARGUMENTS.include?(arg) # rubocop:disable Rails/NegateInclude
!ALLOWLISTED_ARGUMENTS.include?(arg) # rubocop:disable Rails/NegateInclude
end
end
end

View File

@ -371,7 +371,7 @@ function rspec_rerun_previous_failed_tests() {
local test_file_count_threshold=${RSPEC_PREVIOUS_FAILED_TEST_FILE_COUNT_THRESHOLD:-10}
local matching_tests_file=${1}
local rspec_opts=${2}
local test_files="$(cat "${matching_tests_file}")"
local test_files="$(select_existing_files < "${matching_tests_file}")"
local test_file_count=$(wc -w "${matching_tests_file}" | awk {'print $1'})
if [[ "${test_file_count}" -gt "${test_file_count_threshold}" ]]; then

View File

@ -201,6 +201,10 @@ function install_junit_merge_gem() {
run_timed_command "gem install junit_merge --no-document --version 0.1.2"
}
function select_existing_files() {
ruby -e 'print $stdin.read.split(" ").select { |f| File.exist?(f) }.join(" ")'
}
function fail_on_warnings() {
local cmd="$*"
local warning_file

View File

@ -92,7 +92,7 @@ RSpec.describe IssuableCollections do
}
end
it 'only allows whitelisted params' do
it 'only allows allowlisted params' do
is_expected.to include({
'assignee_id' => '1',
'assignee_username' => 'user1',
@ -123,7 +123,7 @@ RSpec.describe IssuableCollections do
}
end
it 'only allows whitelisted params' do
it 'only allows allowlisted params' do
is_expected.to include({
'label_name' => %w[label1 label2],
'assignee_username' => %w[user1 user2]

View File

@ -46,14 +46,6 @@ describe('content_editor/services/create_content_editor', () => {
});
});
it('sets gl-shadow-none! class selector to the tiptapEditor instance', () => {
expect(editor.tiptapEditor.options.editorProps).toMatchObject({
attributes: {
class: 'gl-shadow-none!',
},
});
});
it('allows providing external content editor extensions', () => {
const labelReference = 'this is a ~group::editor';
const { tiptapExtension, serializer } = createTestContentEditorExtension();

View File

@ -1,6 +1,6 @@
import { nextTick } from 'vue';
import { GlIcon, GlCard } from '@gitlab/ui';
import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import {
issuable1,
issuable2,
@ -14,6 +14,7 @@ import {
linkedIssueTypesTextMap,
PathIdSeparator,
} from '~/related_issues/constants';
import RelatedIssuesList from '~/related_issues/components/related_issues_list.vue';
describe('RelatedIssuesBlock', () => {
let wrapper;
@ -21,9 +22,10 @@ describe('RelatedIssuesBlock', () => {
const findToggleButton = () => wrapper.findByTestId('toggle-links');
const findRelatedIssuesBody = () => wrapper.findByTestId('related-issues-body');
const findIssueCountBadgeAddButton = () => wrapper.findByTestId('related-issues-plus-button');
const findAllRelatedIssuesList = () => wrapper.findAllComponents(RelatedIssuesList);
const findRelatedIssuesList = (index) => findAllRelatedIssuesList().at(index);
const createComponent = ({
mountFn = mountExtended,
pathIdSeparator = PathIdSeparator.Issue,
issuableType = TYPE_ISSUE,
canAdmin = false,
@ -35,7 +37,7 @@ describe('RelatedIssuesBlock', () => {
autoCompleteEpics = true,
slots = '',
} = {}) => {
wrapper = mountFn(RelatedIssuesBlock, {
wrapper = shallowMountExtended(RelatedIssuesBlock, {
propsData: {
pathIdSeparator,
issuableType,
@ -94,10 +96,7 @@ describe('RelatedIssuesBlock', () => {
it('displays header text slot data', () => {
const headerText = '<div>custom header text</div>';
createComponent({
mountFn: shallowMountExtended,
slots: { 'header-text': headerText },
});
createComponent({ slots: { 'header-text': headerText } });
expect(wrapper.findByTestId('card-title').html()).toContain(headerText);
});
@ -107,10 +106,7 @@ describe('RelatedIssuesBlock', () => {
it('displays header actions slot data', () => {
const headerActions = '<button data-testid="custom-button">custom button</button>';
createComponent({
mountFn: shallowMountExtended,
slots: { 'header-actions': headerActions },
});
createComponent({ slots: { 'header-actions': headerActions } });
expect(wrapper.findByTestId('custom-button').html()).toBe(headerActions);
});
@ -153,10 +149,6 @@ describe('RelatedIssuesBlock', () => {
});
describe('showCategorizedIssues prop', () => {
const issueList = () => wrapper.findAll('.js-related-issues-token-list-item');
const categorizedHeadings = () => wrapper.findAll('h4');
const headingTextAt = (index) => categorizedHeadings().at(index).text();
describe('when showCategorizedIssues=true', () => {
beforeEach(() =>
createComponent({
@ -166,25 +158,25 @@ describe('RelatedIssuesBlock', () => {
);
it('should render issue tokens items', () => {
expect(issueList()).toHaveLength(3);
expect(findAllRelatedIssuesList()).toHaveLength(3);
});
it('shows "Blocks" heading', () => {
const blocks = linkedIssueTypesTextMap[linkedIssueTypesMap.BLOCKS];
expect(headingTextAt(0)).toBe(blocks);
expect(findRelatedIssuesList(0).props('heading')).toBe(
linkedIssueTypesTextMap[linkedIssueTypesMap.BLOCKS],
);
});
it('shows "Is blocked by" heading', () => {
const isBlockedBy = linkedIssueTypesTextMap[linkedIssueTypesMap.IS_BLOCKED_BY];
expect(headingTextAt(1)).toBe(isBlockedBy);
expect(findRelatedIssuesList(1).props('heading')).toBe(
linkedIssueTypesTextMap[linkedIssueTypesMap.IS_BLOCKED_BY],
);
});
it('shows "Relates to" heading', () => {
const relatesTo = linkedIssueTypesTextMap[linkedIssueTypesMap.RELATES_TO];
expect(headingTextAt(2)).toBe(relatesTo);
expect(findRelatedIssuesList(2).props('heading')).toBe(
linkedIssueTypesTextMap[linkedIssueTypesMap.RELATES_TO],
);
});
});
@ -194,8 +186,9 @@ describe('RelatedIssuesBlock', () => {
showCategorizedIssues: false,
relatedIssues: [issuable1, issuable2, issuable3],
});
expect(issueList()).toHaveLength(3);
expect(categorizedHeadings()).toHaveLength(0);
expect(findAllRelatedIssuesList()).toHaveLength(1);
expect(findRelatedIssuesList(0).props('relatedIssues')).toHaveLength(3);
expect(findRelatedIssuesList(0).props('heading')).toBe('');
});
});
});

View File

@ -24,7 +24,7 @@ exports[`Snippet Description Edit component rendering matches the snapshot 1`] =
</div>
<div
class="js-vue-markdown-field md-area position-relative gfm-form js-expanded"
class="js-vue-markdown-field md-area position-relative gfm-form gl-overflow-hidden js-expanded"
data-uploads-path=""
>
<markdown-header-stub

View File

@ -39,6 +39,8 @@ describe('GroupSelect', () => {
const findEntitySelect = () => wrapper.findComponent(EntitySelect);
const findAlert = () => wrapper.findComponent(GlAlert);
const handleInput = jest.fn();
// Helpers
const createComponent = ({ props = {} } = {}) => {
wrapper = shallowMountExtended(GroupSelect, {
@ -52,6 +54,9 @@ describe('GroupSelect', () => {
GlAlert,
EntitySelect,
},
listeners: {
input: handleInput,
},
});
};
const openListbox = () => findListbox().vm.$emit('shown');
@ -132,4 +137,11 @@ describe('GroupSelect', () => {
expect(findAlert().exists()).toBe(true);
expect(findAlert().text()).toBe(FETCH_GROUPS_ERROR);
});
it('forwards events to the parent scope via `v-on="$listeners"`', () => {
createComponent();
findEntitySelect().vm.$emit('input');
expect(handleInput).toHaveBeenCalledTimes(1);
});
});

View File

@ -45,6 +45,8 @@ describe('ProjectSelect', () => {
const findEntitySelect = () => wrapper.findComponent(EntitySelect);
const findAlert = () => wrapper.findComponent(GlAlert);
const handleInput = jest.fn();
// Helpers
const createComponent = ({ props = {} } = {}) => {
wrapper = mountExtended(ProjectSelect, {
@ -59,6 +61,9 @@ describe('ProjectSelect', () => {
GlAlert,
EntitySelect,
},
listeners: {
input: handleInput,
},
});
};
const openListbox = () => findListbox().vm.$emit('shown');
@ -255,4 +260,11 @@ describe('ProjectSelect', () => {
expect(findAlert().exists()).toBe(true);
expect(findAlert().text()).toBe(FETCH_PROJECTS_ERROR);
});
it('forwards events to the parent scope via `v-on="$listeners"`', () => {
createComponent();
findEntitySelect().vm.$emit('input');
expect(handleInput).toHaveBeenCalledTimes(1);
});
});

View File

@ -31,6 +31,12 @@ RSpec.describe Gitlab::Observability, feature_category: :error_tracking do
end
end
describe '.oauth_url' do
subject { described_class.oauth_url }
it { is_expected.to eq("#{described_class.observability_url}/v1/auth/start") }
end
describe '.build_full_url' do
let_it_be(:group) { build_stubbed(:group, id: 123) }
let(:observability_url) { described_class.observability_url }
@ -148,6 +154,27 @@ RSpec.describe Gitlab::Observability, feature_category: :error_tracking do
end
end
describe '.tracing_enabled?' do
let_it_be(:project) { create(:project, :repository) }
it 'returns true if feature is enabled globally' do
expect(described_class.tracing_enabled?(project)).to eq(true)
end
it 'returns true if feature is enabled for the project' do
stub_feature_flags(observability_tracing: false)
stub_feature_flags(observability_tracing: project)
expect(described_class.tracing_enabled?(project)).to eq(true)
end
it 'returns false if feature is disabled globally' do
stub_feature_flags(observability_tracing: false)
expect(described_class.tracing_enabled?(project)).to eq(false)
end
end
describe '.allowed_for_action?' do
let(:group) { build_stubbed(:group) }
let(:user) { build_stubbed(:user) }

View File

@ -7,7 +7,9 @@ RSpec.describe Sidebars::Projects::Menus::MonitorMenu, feature_category: :naviga
let(:user) { project.first_owner }
let(:show_cluster_hint) { true }
let(:context) { Sidebars::Projects::Context.new(current_user: user, container: project, show_cluster_hint: show_cluster_hint) }
let(:context) do
Sidebars::Projects::Context.new(current_user: user, container: project, show_cluster_hint: show_cluster_hint)
end
subject { described_class.new(context) }
@ -86,5 +88,19 @@ RSpec.describe Sidebars::Projects::Menus::MonitorMenu, feature_category: :naviga
it_behaves_like 'access rights checks'
end
describe 'Tracing' do
let(:item_id) { :tracing }
specify { is_expected.not_to be_nil }
describe 'when feature is disabled' do
before do
stub_feature_flags(observability_tracing: false)
end
specify { is_expected.to be_nil }
end
end
end
end

View File

@ -15,6 +15,7 @@ RSpec.describe Sidebars::Projects::SuperSidebarMenus::MonitorMenu, feature_categ
it 'defines list of NilMenuItem placeholders' do
expect(items.map(&:class).uniq).to eq([Sidebars::NilMenuItem])
expect(items.map(&:item_id)).to eq([
:tracing,
:error_tracking,
:alert_management,
:incidents,

View File

@ -17,6 +17,10 @@ RSpec.describe Groups::ObservabilityController, feature_category: :tracing do
end
it_behaves_like 'observability csp policy' do
before_all do
group.add_developer(user)
end
let(:tested_path) { path }
end

View File

@ -17,6 +17,11 @@ RSpec.describe Projects::IssuesController, feature_category: :team_planning do
describe 'GET #new' do
include_context 'group project issue'
before do
group.add_developer(user)
login_as(user)
end
it_behaves_like "observability csp policy", described_class do
let(:tested_path) do
new_project_issue_path(project)
@ -26,11 +31,13 @@ RSpec.describe Projects::IssuesController, feature_category: :team_planning do
describe 'GET #show' do
before do
group.add_developer(user)
login_as(user)
end
it_behaves_like "observability csp policy", described_class do
include_context 'group project issue'
let(:tested_path) do
project_issue_path(project, issue)
end

View File

@ -6,8 +6,13 @@ RSpec.describe 'merge requests creations', feature_category: :code_review_workfl
describe 'GET /:namespace/:project/merge_requests/new' do
include ProjectForksHelper
let(:project) { create(:project, :repository) }
let(:user) { project.first_owner }
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, :repository, group: group) }
let_it_be(:user) { create(:user) }
before_all do
group.add_developer(user)
end
before do
login_as(user)
@ -26,16 +31,13 @@ RSpec.describe 'merge requests creations', feature_category: :code_review_workfl
end
it_behaves_like "observability csp policy", Projects::MergeRequests::CreationsController do
let_it_be(:group) { create(:group) }
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, group: group) }
let(:tested_path) do
project_new_merge_request_path(project, merge_request: {
title: 'Some feature',
source_branch: 'fix',
target_branch: 'feature',
target_project: project,
source_project: project
source_branch: 'fix',
target_branch: 'feature',
target_project: project,
source_project: project
})
end
end

View File

@ -16,6 +16,7 @@ RSpec.describe Projects::MergeRequestsController, feature_category: :source_code
context 'when logged in' do
before do
group.add_developer(user)
login_as(user)
end

View File

@ -0,0 +1,56 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Projects::TracingController, feature_category: :tracing do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
let(:path) { nil }
let(:observability_tracing_ff) { true }
subject do
get path
response
end
describe 'GET #index' do
before do
stub_feature_flags(observability_tracing: observability_tracing_ff)
sign_in(user)
end
let(:path) { project_tracing_index_path(project) }
it_behaves_like 'observability csp policy' do
before_all do
project.add_developer(user)
end
let(:tested_path) { path }
end
context 'when user does not have permissions' do
it 'returns 404' do
expect(subject).to have_gitlab_http_status(:not_found)
end
end
context 'when user has permissions' do
before_all do
project.add_developer(user)
end
it 'returns 200' do
expect(subject).to have_gitlab_http_status(:ok)
end
context 'when feature is disabled' do
let(:observability_tracing_ff) { false }
it 'returns 404' do
expect(subject).to have_gitlab_http_status(:not_found)
end
end
end
end
end

View File

@ -41,10 +41,10 @@ RSpec.describe RuboCop::Cop::AvoidReturnFromBlocks do
RUBY
end
shared_examples 'examples with whitelisted method' do |whitelisted_method|
it "doesn't flag violation for return inside #{whitelisted_method}" do
shared_examples 'examples with allowlisted method' do |allowlisted_method|
it "doesn't flag violation for return inside #{allowlisted_method}" do
expect_no_offenses(<<~RUBY)
items.#{whitelisted_method} do |item|
items.#{allowlisted_method} do |item|
do_something
return if something_else
end
@ -52,8 +52,8 @@ RSpec.describe RuboCop::Cop::AvoidReturnFromBlocks do
end
end
%i[each each_filename times loop].each do |whitelisted_method|
it_behaves_like 'examples with whitelisted method', whitelisted_method
%i[each each_filename times loop].each do |allowlisted_method|
it_behaves_like 'examples with allowlisted method', allowlisted_method
end
shared_examples 'examples with def methods' do |def_method|

View File

@ -12,8 +12,8 @@ RSpec.describe RuboCop::Cop::Graphql::IDType do
TYPE
end
context 'whitelisted arguments' do
RuboCop::Cop::Graphql::IDType::WHITELISTED_ARGUMENTS.each do |arg|
context 'allowlisted arguments' do
RuboCop::Cop::Graphql::IDType::ALLOWLISTED_ARGUMENTS.each do |arg|
it "does not add an offense for calls to #argument with #{arg} as argument name" do
expect_no_offenses(<<~TYPE.strip)
argument #{arg}, GraphQL::Types::ID, some: other, params: do_not_matter

View File

@ -15,7 +15,7 @@ RSpec.describe DesignManagement::GenerateImageVersionsService, feature_category:
.from(nil).to(CarrierWave::SanitizedFile)
end
it 'skips generating image versions if the mime type is not whitelisted' do
it 'skips generating image versions if the mime type is not allowlisted' do
stub_const('DesignManagement::DesignV432x230Uploader::MIME_TYPE_ALLOWLIST', [])
described_class.new(version).execute

View File

@ -9,7 +9,7 @@ RSpec.describe Projects::DownloadService, feature_category: :groups_and_projects
@project = create(:project, creator_id: @user.id, namespace: @user.namespace)
end
context 'for a URL that is not on whitelist' do
context 'for a URL that is not on allowlist' do
before do
url = 'https://code.jquery.com/jquery-2.1.4.min.js'
@link_to_file = download_file(@project, url)
@ -18,7 +18,7 @@ RSpec.describe Projects::DownloadService, feature_category: :groups_and_projects
it { expect(@link_to_file).to eq(nil) }
end
context 'for URLs that are on the whitelist' do
context 'for URLs that are on the allowlist' do
before do
# `ssrf_filter` resolves the hostname. See https://github.com/carrierwaveuploader/carrierwave/commit/91714adda998bc9e8decf5b1f5d260d808761304
stub_request(:get, %r{http://[\d.]+/rails_sample.jpg}).to_return(body: File.read(Rails.root + 'spec/fixtures/rails_sample.jpg'))

View File

@ -92,7 +92,7 @@ module ExportFileHelper
end
# Returns the offended ObjectWithParent object if a sensitive word is found inside a hash,
# excluding the whitelisted safe hashes.
# excluding the allowlisted safe hashes.
def find_sensitive_attributes(sensitive_word, project_hash)
loop do
object_with_parent = deep_find_with_parent(sensitive_word, project_hash)

View File

@ -82,6 +82,7 @@ RSpec.shared_context 'project navbar structure' do
{
nav_item: _('Monitor'),
nav_sub_items: [
_('Tracing'),
_('Error Tracking'),
_('Alerts'),
_('Incidents')

View File

@ -25,7 +25,7 @@ RSpec.shared_examples 'default allowlist' do
expect(filter(act).to_html).to eq exp
end
it 'allows whitelisted HTML tags from the user' do
it 'allows allowlisted HTML tags from the user' do
exp = act = "<dl>\n<dt>Term</dt>\n<dd>Definition</dd>\n</dl>"
expect(filter(act).to_html).to eq exp
end

View File

@ -5,23 +5,28 @@
# It requires the following variables declared in the context including this example:
#
# - `tested_path`: the path under test
# - `user`: the test user
# - `group`: the test group
#
# e.g.
#
# ```
# let_it_be(:group) { create(:group) }
# let_it_be(:user) { create(:user) }
# it_behaves_like "observability csp policy" do
# let(:tested_path) { ....the path under test }
# end
# ```
#
# Note that the context's user is expected to be logged-in and the
# related resources (group, project, etc) are supposed to be provided with proper
# permissions already, e.g.
#
# before do
# login_as(user)
# group.add_developer(user)
# end
#
# It optionally supports specifying the controller class handling the tested path as a parameter, e.g.
#
# ```
# it_behaves_like "observability csp policy", Groups::ObservabilityController
# it_behaves_like "observability csp policy", Projects::TracingController
# ```
# (If not specified it will default to `described_class`)
#
@ -41,9 +46,6 @@ RSpec.shared_examples 'observability csp policy' do |controller_class = describe
before do
setup_csp_for_controller(controller_class, csp, any_time: true)
group.add_developer(user)
login_as(user)
stub_feature_flags(observability_group_tab: true)
end
subject do
@ -59,93 +61,127 @@ RSpec.shared_examples 'observability csp policy' do |controller_class = describe
end
end
context 'when observability is disabled' do
let(:csp) do
ActionDispatch::ContentSecurityPolicy.new do |p|
p.frame_src 'https://something.test'
describe 'frame-src' do
context 'when frame-src exists in the CSP config' do
let(:csp) do
ActionDispatch::ContentSecurityPolicy.new do |p|
p.frame_src 'https://something.test'
end
end
it 'appends the proper url to frame-src CSP directives' do
expect(subject).to include(
"frame-src https://something.test #{observability_url} #{signin_url} #{oauth_url}")
end
end
before do
stub_feature_flags(observability_group_tab: false)
context 'when signin url is already present in the policy' do
let(:csp) do
ActionDispatch::ContentSecurityPolicy.new do |p|
p.frame_src signin_url
end
end
it 'does not append signin again' do
expect(subject).to include(
"frame-src #{signin_url} #{observability_url} #{oauth_url};")
end
end
it 'does not add observability urls to the csp header' do
expect(subject).to include("frame-src https://something.test")
expect(subject).not_to include("#{observability_url} #{signin_url} #{oauth_url}")
context 'when oauth url is already present in the policy' do
let(:csp) do
ActionDispatch::ContentSecurityPolicy.new do |p|
p.frame_src oauth_url
end
end
it 'does not append oauth again' do
expect(subject).to include(
"frame-src #{oauth_url} #{observability_url} #{signin_url};")
end
end
context 'when default-src exists in the CSP config' do
let(:csp) do
ActionDispatch::ContentSecurityPolicy.new do |p|
p.default_src 'https://something.test'
end
end
it 'does not change default-src' do
expect(subject).to include(
"default-src https://something.test;")
end
it 'appends the proper url to frame-src CSP directives' do
expect(subject).to include(
"frame-src https://something.test #{observability_url} #{signin_url} #{oauth_url}")
end
end
context 'when frame-src and default-src exist in the CSP config' do
let(:csp) do
ActionDispatch::ContentSecurityPolicy.new do |p|
p.default_src 'https://something_default.test'
p.frame_src 'https://something.test'
end
end
it 'appends to frame-src CSP directives' do
expect(subject).to include(
"frame-src https://something.test #{observability_url} #{signin_url} #{oauth_url}")
expect(subject).to include(
"default-src https://something_default.test")
end
end
end
context 'when frame-src exists in the CSP config' do
let(:csp) do
ActionDispatch::ContentSecurityPolicy.new do |p|
p.frame_src 'https://something.test'
describe 'connect-src' do
context 'when connect-src exists in the CSP config' do
let(:csp) do
ActionDispatch::ContentSecurityPolicy.new do |p|
p.connect_src 'https://something.test'
end
end
it 'appends the proper url to connect-src CSP directives' do
expect(subject).to include(
"connect-src https://something.test localhost #{observability_url}")
end
end
it 'appends the proper url to frame-src CSP directives' do
expect(subject).to include(
"frame-src https://something.test #{observability_url} #{signin_url} #{oauth_url}")
end
end
context 'when default-src exists in the CSP config' do
let(:csp) do
ActionDispatch::ContentSecurityPolicy.new do |p|
p.default_src 'https://something.test'
end
end
context 'when signin is already present in the policy' do
let(:csp) do
ActionDispatch::ContentSecurityPolicy.new do |p|
p.frame_src signin_url
it 'does not change default-src' do
expect(subject).to include(
"default-src https://something.test;")
end
it 'appends the proper url to connect-src CSP directives' do
expect(subject).to include(
"connect-src https://something.test localhost #{observability_url}")
end
end
it 'does not append signin again' do
expect(subject).to include(
"frame-src #{signin_url} #{observability_url} #{oauth_url};")
end
end
context 'when oauth is already present in the policy' do
let(:csp) do
ActionDispatch::ContentSecurityPolicy.new do |p|
p.frame_src oauth_url
context 'when connect-src and default-src exist in the CSP config' do
let(:csp) do
ActionDispatch::ContentSecurityPolicy.new do |p|
p.default_src 'https://something_default.test'
p.connect_src 'https://something.test'
end
end
end
it 'does not append oauth again' do
expect(subject).to include(
"frame-src #{oauth_url} #{observability_url} #{signin_url};")
end
end
context 'when default-src exists in the CSP config' do
let(:csp) do
ActionDispatch::ContentSecurityPolicy.new do |p|
p.default_src 'https://something.test'
it 'appends to connect-src CSP directives' do
expect(subject).to include(
"connect-src https://something.test localhost #{observability_url}")
expect(subject).to include(
"default-src https://something_default.test")
end
end
it 'does not change default-src' do
expect(subject).to include(
"default-src https://something.test;")
end
it 'appends the proper url to frame-src CSP directives' do
expect(subject).to include(
"frame-src https://something.test #{observability_url} #{signin_url} #{oauth_url}")
end
end
context 'when frame-src and default-src exist in the CSP config' do
let(:csp) do
ActionDispatch::ContentSecurityPolicy.new do |p|
p.default_src 'https://something_default.test'
p.frame_src 'https://something.test'
end
end
it 'appends to frame-src CSP directives' do
expect(subject).to include(
"frame-src https://something.test #{observability_url} #{signin_url} #{oauth_url}")
expect(subject).to include(
"default-src https://something_default.test")
end
end
end

View File

@ -47,7 +47,7 @@ RSpec.describe AvatarUploader do
end
end
context 'accept whitelist file content type' do
context 'accept allowlist file content type' do
# We need to feed through a valid path, but we force the parsed mime type
# in a stub below so we can set any path.
let_it_be(:path) { File.join('spec', 'fixtures', 'video_sample.mp4') }
@ -61,13 +61,13 @@ RSpec.describe AvatarUploader do
end
end
context 'upload non-whitelisted file content type' do
context 'upload denylisted file content type' do
let_it_be(:path) { File.join('spec', 'fixtures', 'sanitized.svg') }
it_behaves_like 'denied carrierwave upload'
end
context 'upload misnamed non-whitelisted file content type' do
context 'upload misnamed denylisted file content type' do
let_it_be(:path) { File.join('spec', 'fixtures', 'not_a_png.png') }
it_behaves_like 'denied carrierwave upload'

View File

@ -58,7 +58,7 @@ RSpec.describe DesignManagement::DesignV432x230Uploader do
)
end
context 'accept whitelist file content type' do
context 'accept allowlisted file content type' do
# We need to feed through a valid path, but we force the parsed mime type
# in a stub below so we can set any path.
let_it_be(:path) { File.join('spec', 'fixtures', 'dk.png') }
@ -72,13 +72,13 @@ RSpec.describe DesignManagement::DesignV432x230Uploader do
end
end
context 'upload non-whitelisted file content type' do
context 'upload denylisted file content type' do
let_it_be(:path) { File.join('spec', 'fixtures', 'logo_sample.svg') }
it_behaves_like 'denied carrierwave upload'
end
context 'upload misnamed non-whitelisted file content type' do
context 'upload misnamed denylisted file content type' do
let_it_be(:path) { File.join('spec', 'fixtures', 'not_a_png.png') }
it_behaves_like 'denied carrierwave upload'

View File

@ -6,7 +6,7 @@ RSpec.describe FaviconUploader do
let_it_be(:model) { build_stubbed(:user) }
let_it_be(:uploader) { described_class.new(model, :favicon) }
context 'accept whitelist file content type' do
context 'accept allowlist file content type' do
include_context 'ignore extension allowlist check'
# We need to feed through a valid path, but we force the parsed mime type
@ -22,7 +22,7 @@ RSpec.describe FaviconUploader do
end
end
context 'upload non-whitelisted file content type' do
context 'upload denylisted file content type' do
include_context 'ignore extension allowlist check'
let_it_be(:path) { File.join('spec', 'fixtures', 'sanitized.svg') }
@ -30,7 +30,7 @@ RSpec.describe FaviconUploader do
it_behaves_like 'denied carrierwave upload'
end
context 'upload misnamed non-whitelisted file content type' do
context 'upload misnamed denylisted file content type' do
include_context 'ignore extension allowlist check'
let_it_be(:path) { File.join('spec', 'fixtures', 'not_a_png.png') }

View File

@ -29,7 +29,7 @@ RSpec.describe CronValidator do
expect(subject.valid?).to be_falsy
end
context 'cron field is not whitelisted' do
context 'cron field is not allowlisted' do
subject do
Class.new do
include ActiveModel::Model
@ -43,7 +43,7 @@ RSpec.describe CronValidator do
it 'raises an error' do
subject.cron_partytime = '0 23 * * 5'
expect { subject.valid? }.to raise_error(StandardError, "Non-whitelisted attribute")
expect { subject.valid? }.to raise_error(StandardError, "Non-allowlisted attribute")
end
end
end