diff options
85 files changed, 743 insertions, 476 deletions
diff --git a/.gitlab/ci/static-analysis.gitlab-ci.yml b/.gitlab/ci/static-analysis.gitlab-ci.yml index b9d73d7770d..29887881da5 100644 --- a/.gitlab/ci/static-analysis.gitlab-ci.yml +++ b/.gitlab/ci/static-analysis.gitlab-ci.yml @@ -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})" diff --git a/.rubocop_todo/naming/inclusive_language.yml b/.rubocop_todo/naming/inclusive_language.yml index 9d1e98f87d3..271286d4752 100644 --- a/.rubocop_todo/naming/inclusive_language.yml +++ b/.rubocop_todo/naming/inclusive_language.yml @@ -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' diff --git a/app/assets/javascripts/content_editor/components/content_editor.vue b/app/assets/javascripts/content_editor/components/content_editor.vue index 344df7a35c3..c6b605cd92f 100644 --- a/app/assets/javascripts/content_editor/components/content_editor.vue +++ b/app/assets/javascripts/content_editor/components/content_editor.vue @@ -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> diff --git a/app/assets/javascripts/content_editor/components/formatting_toolbar.vue b/app/assets/javascripts/content_editor/components/formatting_toolbar.vue index 6877f26b7d2..dc27278d255 100644 --- a/app/assets/javascripts/content_editor/components/formatting_toolbar.vue +++ b/app/assets/javascripts/content_editor/components/formatting_toolbar.vue @@ -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> diff --git a/app/assets/javascripts/content_editor/services/create_content_editor.js b/app/assets/javascripts/content_editor/services/create_content_editor.js index f7d189e443f..51e41ceefaf 100644 --- a/app/assets/javascripts/content_editor/services/create_content_editor.js +++ b/app/assets/javascripts/content_editor/services/create_content_editor.js @@ -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, }); diff --git a/app/assets/javascripts/issues/related_merge_requests/components/related_merge_requests.vue b/app/assets/javascripts/issues/related_merge_requests/components/related_merge_requests.vue index cc3e2b145ed..cbec10b4ebe 100644 --- a/app/assets/javascripts/issues/related_merge_requests/components/related_merge_requests.vue +++ b/app/assets/javascripts/issues/related_merge_requests/components/related_merge_requests.vue @@ -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> diff --git a/app/assets/javascripts/issues/show/components/incidents/timeline_events_form.vue b/app/assets/javascripts/issues/show/components/incidents/timeline_events_form.vue index 8267c0130a3..2a59b7a2042 100644 --- a/app/assets/javascripts/issues/show/components/incidents/timeline_events_form.vue +++ b/app/assets/javascripts/issues/show/components/incidents/timeline_events_form.vue @@ -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" diff --git a/app/assets/javascripts/notes/components/comment_field_layout.vue b/app/assets/javascripts/notes/components/comment_field_layout.vue index bde7d219e9f..cefcc1b0c98 100644 --- a/app/assets/javascripts/notes/components/comment_field_layout.vue +++ b/app/assets/javascripts/notes/components/comment_field_layout.vue @@ -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> diff --git a/app/assets/javascripts/notes/components/noteable_discussion.vue b/app/assets/javascripts/notes/components/noteable_discussion.vue index 0b3ba13847b..1c98904aacc 100644 --- a/app/assets/javascripts/notes/components/noteable_discussion.vue +++ b/app/assets/javascripts/notes/components/noteable_discussion.vue @@ -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 diff --git a/app/assets/javascripts/related_issues/components/related_issues_block.vue b/app/assets/javascripts/related_issues/components/related_issues_block.vue index 6ccf53624cf..1044d25c1a3 100644 --- a/app/assets/javascripts/related_issues/components/related_issues_block.vue +++ b/app/assets/javascripts/related_issues/components/related_issues_block.vue @@ -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 diff --git a/app/assets/javascripts/vue_shared/components/entity_select/group_select.vue b/app/assets/javascripts/vue_shared/components/entity_select/group_select.vue index ff137d764ee..71e3bf4ff63 100644 --- a/app/assets/javascripts/vue_shared/components/entity_select/group_select.vue +++ b/app/assets/javascripts/vue_shared/components/entity_select/group_select.vue @@ -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">{{ diff --git a/app/assets/javascripts/vue_shared/components/entity_select/project_select.vue b/app/assets/javascripts/vue_shared/components/entity_select/project_select.vue index 7af3819f2a5..13a825a68f6 100644 --- a/app/assets/javascripts/vue_shared/components/entity_select/project_select.vue +++ b/app/assets/javascripts/vue_shared/components/entity_select/project_select.vue @@ -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> diff --git a/app/assets/javascripts/vue_shared/components/markdown/editor_mode_switcher.vue b/app/assets/javascripts/vue_shared/components/markdown/editor_mode_switcher.vue index 5cf5fbd5323..81456aed8d7 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/editor_mode_switcher.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/editor_mode_switcher.vue @@ -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 diff --git a/app/assets/javascripts/vue_shared/components/markdown/field.vue b/app/assets/javascripts/vue_shared/components/markdown/field.vue index 268352a9c9c..7c569763a75 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/field.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/field.vue @@ -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 diff --git a/app/assets/javascripts/vue_shared/components/markdown/header.vue b/app/assets/javascripts/vue_shared/components/markdown/header.vue index 0899b752cbc..00390194414 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/header.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/header.vue @@ -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" diff --git a/app/assets/javascripts/vue_shared/components/markdown/markdown_editor.vue b/app/assets/javascripts/vue_shared/components/markdown/markdown_editor.vue index 9638baa1dea..186b70a9ecd 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/markdown_editor.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/markdown_editor.vue @@ -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 diff --git a/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue b/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue index 50f63c68690..7cce42629d6 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue @@ -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> diff --git a/app/assets/javascripts/work_items/components/work_item_links/work_item_links.vue b/app/assets/javascripts/work_items/components/work_item_links/work_item_links.vue index 9b3b4df5db6..bfc6ceefccc 100644 --- a/app/assets/javascripts/work_items/components/work_item_links/work_item_links.vue +++ b/app/assets/javascripts/work_items/components/work_item_links/work_item_links.vue @@ -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> diff --git a/app/assets/stylesheets/components/content_editor.scss b/app/assets/stylesheets/components/content_editor.scss index c2e25e1e696..c1a7c4d4d86 100644 --- a/app/assets/stylesheets/components/content_editor.scss +++ b/app/assets/stylesheets/components/content_editor.scss @@ -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 { diff --git a/app/assets/stylesheets/framework/markdown_area.scss b/app/assets/stylesheets/framework/markdown_area.scss index 5fdab7891ec..f8f54567ef2 100644 --- a/app/assets/stylesheets/framework/markdown_area.scss +++ b/app/assets/stylesheets/framework/markdown_area.scss @@ -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 { diff --git a/app/assets/stylesheets/framework/new_card.scss b/app/assets/stylesheets/framework/new_card.scss index 3981b713564..883690681ce 100644 --- a/app/assets/stylesheets/framework/new_card.scss +++ b/app/assets/stylesheets/framework/new_card.scss @@ -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; diff --git a/app/assets/stylesheets/pages/note_form.scss b/app/assets/stylesheets/pages/note_form.scss index d442958ad61..8fe04ddc352 100644 --- a/app/assets/stylesheets/pages/note_form.scss +++ b/app/assets/stylesheets/pages/note_form.scss @@ -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); } - } - .comment-warning-wrapper:focus-within { - @include gl-focus; - } -} + .note-textarea-rounded-bottom { + border-bottom-left-radius: calc(#{$border-radius-large} - 1px); + border-bottom-right-radius: calc(#{$border-radius-large} - 1px); + } -.md-area:focus-within { - @include gl-focus; + // Disable inner focus on fullscreen + .zen-backdrop.fullscreen textarea:focus { + box-shadow: none; + } + } } .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; - } } diff --git a/app/controllers/admin/application_settings/appearances_controller.rb b/app/controllers/admin/application_settings/appearances_controller.rb index 719e8e4a913..1a1e85d48da 100644 --- a/app/controllers/admin/application_settings/appearances_controller.rb +++ b/app/controllers/admin/application_settings/appearances_controller.rb @@ -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 diff --git a/app/controllers/concerns/observability/content_security_policy.rb b/app/controllers/concerns/observability/content_security_policy.rb index 1e25dc492a0..e51d986d36c 100644 --- a/app/controllers/concerns/observability/content_security_policy.rb +++ b/app/controllers/concerns/observability/content_security_policy.rb @@ -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 diff --git a/app/controllers/concerns/requires_whitelisted_monitoring_client.rb b/app/controllers/concerns/requires_allowlisted_monitoring_client.rb index ef3d281589a..ad6d4dc548c 100644 --- a/app/controllers/concerns/requires_whitelisted_monitoring_client.rb +++ b/app/controllers/concerns/requires_allowlisted_monitoring_client.rb @@ -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? diff --git a/app/controllers/health_check_controller.rb b/app/controllers/health_check_controller.rb index a2abed7ba4e..a85629985ba 100644 --- a/app/controllers/health_check_controller.rb +++ b/app/controllers/health_check_controller.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true class HealthCheckController < HealthCheck::HealthCheckController - include RequiresWhitelistedMonitoringClient + include RequiresAllowlistedMonitoringClient end diff --git a/app/controllers/health_controller.rb b/app/controllers/health_controller.rb index 5fac7c0d663..1381999ab4c 100644 --- a/app/controllers/health_controller.rb +++ b/app/controllers/health_controller.rb @@ -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 diff --git a/app/controllers/metrics_controller.rb b/app/controllers/metrics_controller.rb index 3dfa8d7b11e..9f41c092fa0 100644 --- a/app/controllers/metrics_controller.rb +++ b/app/controllers/metrics_controller.rb @@ -2,7 +2,7 @@ # rubocop:disable Rails/ApplicationController class MetricsController < ActionController::Base - include RequiresWhitelistedMonitoringClient + include RequiresAllowlistedMonitoringClient protect_from_forgery with: :exception, prepend: true diff --git a/app/controllers/projects/tracing_controller.rb b/app/controllers/projects/tracing_controller.rb new file mode 100644 index 00000000000..71ca03deb8c --- /dev/null +++ b/app/controllers/projects/tracing_controller.rb @@ -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 diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb index be9306ce80b..6746e6549ec 100644 --- a/app/helpers/blob_helper.rb +++ b/app/helpers/blob_helper.rb @@ -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) diff --git a/app/services/projects/download_service.rb b/app/services/projects/download_service.rb index 72cb3997045..22104409199 100644 --- a/app/services/projects/download_service.rb +++ b/app/services/projects/download_service.rb @@ -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 diff --git a/app/validators/cron_validator.rb b/app/validators/cron_validator.rb index 91b9cfcccc4..c12b29410d4 100644 --- a/app/validators/cron_validator.rb +++ b/app/validators/cron_validator.rb @@ -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 diff --git a/app/views/shared/_md_preview.html.haml b/app/views/shared/_md_preview.html.haml index e4fc3ebf23c..1fd430527a1 100644 --- a/app/views/shared/_md_preview.html.haml +++ b/app/views/shared/_md_preview.html.haml @@ -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 diff --git a/app/views/shared/notes/_hints.html.haml b/app/views/shared/notes/_hints.html.haml index 9be87b0a095..23ce38d50e0 100644 --- a/app/views/shared/notes/_hints.html.haml +++ b/app/views/shared/notes/_hints.html.haml @@ -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 diff --git a/config/feature_flags/development/observability_tracing.yml b/config/feature_flags/development/observability_tracing.yml new file mode 100644 index 00000000000..a32d8409608 --- /dev/null +++ b/config/feature_flags/development/observability_tracing.yml @@ -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 diff --git a/config/feature_flags/development/packages_dependency_proxy_maven.yml b/config/feature_flags/development/packages_dependency_proxy_maven.yml new file mode 100644 index 00000000000..8cf2f5a2879 --- /dev/null +++ b/config/feature_flags/development/packages_dependency_proxy_maven.yml @@ -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 diff --git a/config/routes/project.rb b/config/routes/project.rb index 533e6c63e24..787d95669d1 100644 --- a/config/routes/project.rb +++ b/config/routes/project.rb @@ -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 diff --git a/db/docs/dependency_proxy_packages_settings.yml b/db/docs/dependency_proxy_packages_settings.yml index dcb43553f81..b506848e899 100644 --- a/db/docs/dependency_proxy_packages_settings.yml +++ b/db/docs/dependency_proxy_packages_settings.yml @@ -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' diff --git a/doc/development/pipelines/internals.md b/doc/development/pipelines/internals.md index be72fc50988..c0d7bbd3713 100644 --- a/doc/development/pipelines/internals.md +++ b/doc/development/pipelines/internals.md @@ -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 diff --git a/doc/subscriptions/gitlab_com/index.md b/doc/subscriptions/gitlab_com/index.md index 73f9f36ecd6..8cd5777e4cb 100644 --- a/doc/subscriptions/gitlab_com/index.md +++ b/doc/subscriptions/gitlab_com/index.md @@ -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. diff --git a/doc/update/index.md b/doc/update/index.md index a07532dda88..5f6a7c052e6 100644 --- a/doc/update/index.md +++ b/doc/update/index.md @@ -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 diff --git a/doc/user/admin_area/settings/sign_in_restrictions.md b/doc/user/admin_area/settings/sign_in_restrictions.md index 3b79e55f998..c84f2a12db9 100644 --- a/doc/user/admin_area/settings/sign_in_restrictions.md +++ b/doc/user/admin_area/settings/sign_in_restrictions.md @@ -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). diff --git a/doc/user/application_security/dependency_scanning/index.md b/doc/user/application_security/dependency_scanning/index.md index f9a6ffa8228..15fed4f2adc 100644 --- a/doc/user/application_security/dependency_scanning/index.md +++ b/doc/user/application_security/dependency_scanning/index.md @@ -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 diff --git a/doc/user/application_security/iac_scanning/index.md b/doc/user/application_security/iac_scanning/index.md index 8e2f54fed44..83dcfb61772 100644 --- a/doc/user/application_security/iac_scanning/index.md +++ b/doc/user/application_security/iac_scanning/index.md @@ -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 diff --git a/doc/user/application_security/index.md b/doc/user/application_security/index.md index 61d3b463193..56a79191833 100644 --- a/doc/user/application_security/index.md +++ b/doc/user/application_security/index.md @@ -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 diff --git a/doc/user/application_security/sast/index.md b/doc/user/application_security/sast/index.md index 2008375d2a2..657ad904223 100644 --- a/doc/user/application_security/sast/index.md +++ b/doc/user/application_security/sast/index.md @@ -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 diff --git a/doc/user/application_security/secret_detection/index.md b/doc/user/application_security/secret_detection/index.md index c6928d3679b..0a969d51f9e 100644 --- a/doc/user/application_security/secret_detection/index.md +++ b/doc/user/application_security/secret_detection/index.md @@ -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 diff --git a/doc/user/search/command_palette.md b/doc/user/search/command_palette.md new file mode 100644 index 00000000000..138c19be778 --- /dev/null +++ b/doc/user/search/command_palette.md @@ -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. diff --git a/lib/api/helpers/packages/maven.rb b/lib/api/helpers/packages/maven.rb new file mode 100644 index 00000000000..694a1ec6436 --- /dev/null +++ b/lib/api/helpers/packages/maven.rb @@ -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 diff --git a/lib/api/maven_packages.rb b/lib/api/maven_packages.rb index 241cd93f380..eccc55ed158 100644 --- a/lib/api/maven_packages.rb +++ b/lib/api/maven_packages.rb @@ -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? diff --git a/lib/gitlab/git/hook_env.rb b/lib/gitlab/git/hook_env.rb index f93ab19fc65..2524d4c4cfb 100644 --- a/lib/gitlab/git/hook_env.rb +++ b/lib/gitlab/git/hook_env.rb @@ -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 diff --git a/lib/gitlab/observability.rb b/lib/gitlab/observability.rb index f7f65c91339..0e6089e1d21 100644 --- a/lib/gitlab/observability.rb +++ b/lib/gitlab/observability.rb @@ -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 diff --git a/lib/sidebars/projects/menus/monitor_menu.rb b/lib/sidebars/projects/menus/monitor_menu.rb index a74448d0bdc..87b09e42fe1 100644 --- a/lib/sidebars/projects/menus/monitor_menu.rb +++ b/lib/sidebars/projects/menus/monitor_menu.rb @@ -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) diff --git a/lib/sidebars/projects/super_sidebar_menus/monitor_menu.rb b/lib/sidebars/projects/super_sidebar_menus/monitor_menu.rb index 6e64ac01ffa..0441d3b4a03 100644 --- a/lib/sidebars/projects/super_sidebar_menus/monitor_menu.rb +++ b/lib/sidebars/projects/super_sidebar_menus/monitor_menu.rb @@ -17,6 +17,7 @@ module Sidebars override :configure_menu_items def configure_menu_items [ + :tracing, :error_tracking, :alert_management, :incidents, diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 92bbc28876c..daa40c5f621 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -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 "" diff --git a/rubocop/cop/avoid_return_from_blocks.rb b/rubocop/cop/avoid_return_from_blocks.rb index c6a7a87c548..bc10410af1d 100644 --- a/rubocop/cop/avoid_return_from_blocks.rb +++ b/rubocop/cop/avoid_return_from_blocks.rb @@ -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 diff --git a/rubocop/cop/graphql/id_type.rb b/rubocop/cop/graphql/id_type.rb index c9d9b4ea6eb..53d79751fa8 100644 --- a/rubocop/cop/graphql/id_type.rb +++ b/rubocop/cop/graphql/id_type.rb @@ -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 diff --git a/scripts/rspec_helpers.sh b/scripts/rspec_helpers.sh index fc6086c6109..b559a8de52a 100644 --- a/scripts/rspec_helpers.sh +++ b/scripts/rspec_helpers.sh @@ -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 diff --git a/scripts/utils.sh b/scripts/utils.sh index 9ff8c156234..1ed83c69b0c 100644 --- a/scripts/utils.sh +++ b/scripts/utils.sh @@ -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 diff --git a/spec/controllers/concerns/issuable_collections_spec.rb b/spec/controllers/concerns/issuable_collections_spec.rb index 6fa273bf3d7..9eb0f36cb37 100644 --- a/spec/controllers/concerns/issuable_collections_spec.rb +++ b/spec/controllers/concerns/issuable_collections_spec.rb @@ -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] diff --git a/spec/frontend/content_editor/services/create_content_editor_spec.js b/spec/frontend/content_editor/services/create_content_editor_spec.js index b9a9c3ccd17..b68d57971b9 100644 --- a/spec/frontend/content_editor/services/create_content_editor_spec.js +++ b/spec/frontend/content_editor/services/create_content_editor_spec.js @@ -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(); diff --git a/spec/frontend/issuable/related_issues/components/related_issues_block_spec.js b/spec/frontend/issuable/related_issues/components/related_issues_block_spec.js index fb154e01c7a..a24bffdd363 100644 --- a/spec/frontend/issuable/related_issues/components/related_issues_block_spec.js +++ b/spec/frontend/issuable/related_issues/components/related_issues_block_spec.js @@ -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(''); }); }); }); diff --git a/spec/frontend/snippets/components/__snapshots__/snippet_description_edit_spec.js.snap b/spec/frontend/snippets/components/__snapshots__/snippet_description_edit_spec.js.snap index ec3d028db1a..05c1a6dd11d 100644 --- a/spec/frontend/snippets/components/__snapshots__/snippet_description_edit_spec.js.snap +++ b/spec/frontend/snippets/components/__snapshots__/snippet_description_edit_spec.js.snap @@ -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 diff --git a/spec/frontend/vue_shared/components/entity_select/group_select_spec.js b/spec/frontend/vue_shared/components/entity_select/group_select_spec.js index 83560e367ea..ae551116560 100644 --- a/spec/frontend/vue_shared/components/entity_select/group_select_spec.js +++ b/spec/frontend/vue_shared/components/entity_select/group_select_spec.js @@ -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); + }); }); diff --git a/spec/frontend/vue_shared/components/entity_select/project_select_spec.js b/spec/frontend/vue_shared/components/entity_select/project_select_spec.js index 0a174c98efb..9113152c975 100644 --- a/spec/frontend/vue_shared/components/entity_select/project_select_spec.js +++ b/spec/frontend/vue_shared/components/entity_select/project_select_spec.js @@ -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); + }); }); diff --git a/spec/lib/gitlab/observability_spec.rb b/spec/lib/gitlab/observability_spec.rb index 5082d193197..84d591e2520 100644 --- a/spec/lib/gitlab/observability_spec.rb +++ b/spec/lib/gitlab/observability_spec.rb @@ -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) } diff --git a/spec/lib/sidebars/projects/menus/monitor_menu_spec.rb b/spec/lib/sidebars/projects/menus/monitor_menu_spec.rb index 363822ee5e4..c0787aa9db5 100644 --- a/spec/lib/sidebars/projects/menus/monitor_menu_spec.rb +++ b/spec/lib/sidebars/projects/menus/monitor_menu_spec.rb @@ -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 diff --git a/spec/lib/sidebars/projects/super_sidebar_menus/monitor_menu_spec.rb b/spec/lib/sidebars/projects/super_sidebar_menus/monitor_menu_spec.rb index e59062c7eaf..e5c5204e0b4 100644 --- a/spec/lib/sidebars/projects/super_sidebar_menus/monitor_menu_spec.rb +++ b/spec/lib/sidebars/projects/super_sidebar_menus/monitor_menu_spec.rb @@ -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, diff --git a/spec/requests/groups/observability_controller_spec.rb b/spec/requests/groups/observability_controller_spec.rb index b82cf2b0bad..247535bc990 100644 --- a/spec/requests/groups/observability_controller_spec.rb +++ b/spec/requests/groups/observability_controller_spec.rb @@ -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 diff --git a/spec/requests/projects/issues_controller_spec.rb b/spec/requests/projects/issues_controller_spec.rb index 583fd5f586e..1ae65939c86 100644 --- a/spec/requests/projects/issues_controller_spec.rb +++ b/spec/requests/projects/issues_controller_spec.rb @@ -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 diff --git a/spec/requests/projects/merge_requests/creations_spec.rb b/spec/requests/projects/merge_requests/creations_spec.rb index ace6ef0f7b8..e8a073fef5f 100644 --- a/spec/requests/projects/merge_requests/creations_spec.rb +++ b/spec/requests/projects/merge_requests/creations_spec.rb @@ -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 diff --git a/spec/requests/projects/merge_requests_controller_spec.rb b/spec/requests/projects/merge_requests_controller_spec.rb index 955e6822211..955b6e53686 100644 --- a/spec/requests/projects/merge_requests_controller_spec.rb +++ b/spec/requests/projects/merge_requests_controller_spec.rb @@ -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 diff --git a/spec/requests/projects/tracing_controller_spec.rb b/spec/requests/projects/tracing_controller_spec.rb new file mode 100644 index 00000000000..520e99b120a --- /dev/null +++ b/spec/requests/projects/tracing_controller_spec.rb @@ -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 diff --git a/spec/rubocop/cop/avoid_return_from_blocks_spec.rb b/spec/rubocop/cop/avoid_return_from_blocks_spec.rb index e35705ae791..1b41e140454 100644 --- a/spec/rubocop/cop/avoid_return_from_blocks_spec.rb +++ b/spec/rubocop/cop/avoid_return_from_blocks_spec.rb @@ -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| diff --git a/spec/rubocop/cop/graphql/id_type_spec.rb b/spec/rubocop/cop/graphql/id_type_spec.rb index 3a56753d39e..6eb4890c064 100644 --- a/spec/rubocop/cop/graphql/id_type_spec.rb +++ b/spec/rubocop/cop/graphql/id_type_spec.rb @@ -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 diff --git a/spec/services/design_management/generate_image_versions_service_spec.rb b/spec/services/design_management/generate_image_versions_service_spec.rb index 08442f221fa..d02d472f897 100644 --- a/spec/services/design_management/generate_image_versions_service_spec.rb +++ b/spec/services/design_management/generate_image_versions_service_spec.rb @@ -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 diff --git a/spec/services/projects/download_service_spec.rb b/spec/services/projects/download_service_spec.rb index e062ee04bf4..a0b14a36106 100644 --- a/spec/services/projects/download_service_spec.rb +++ b/spec/services/projects/download_service_spec.rb @@ -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')) diff --git a/spec/support/import_export/export_file_helper.rb b/spec/support/import_export/export_file_helper.rb index ee1b4a3c33a..3be2d39906d 100644 --- a/spec/support/import_export/export_file_helper.rb +++ b/spec/support/import_export/export_file_helper.rb @@ -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) diff --git a/spec/support/shared_contexts/navbar_structure_context.rb b/spec/support/shared_contexts/navbar_structure_context.rb index efb4d244c10..0abf688566a 100644 --- a/spec/support/shared_contexts/navbar_structure_context.rb +++ b/spec/support/shared_contexts/navbar_structure_context.rb @@ -82,6 +82,7 @@ RSpec.shared_context 'project navbar structure' do { nav_item: _('Monitor'), nav_sub_items: [ + _('Tracing'), _('Error Tracking'), _('Alerts'), _('Incidents') diff --git a/spec/support/shared_examples/lib/banzai/filters/sanitization_filter_shared_examples.rb b/spec/support/shared_examples/lib/banzai/filters/sanitization_filter_shared_examples.rb index 99d0bc287a3..e6433f963f4 100644 --- a/spec/support/shared_examples/lib/banzai/filters/sanitization_filter_shared_examples.rb +++ b/spec/support/shared_examples/lib/banzai/filters/sanitization_filter_shared_examples.rb @@ -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 diff --git a/spec/support/shared_examples/observability/csp_shared_examples.rb b/spec/support/shared_examples/observability/csp_shared_examples.rb index 9d6e7e75f4d..9002ccd5878 100644 --- a/spec/support/shared_examples/observability/csp_shared_examples.rb +++ b/spec/support/shared_examples/observability/csp_shared_examples.rb @@ -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 - end - before do - stub_feature_flags(observability_group_tab: false) + 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 - 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}") - end - end + 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 - context 'when frame-src exists in the CSP config' do - let(:csp) do - ActionDispatch::ContentSecurityPolicy.new do |p| - p.frame_src 'https://something.test' + it 'does not append signin again' do + expect(subject).to include( + "frame-src #{signin_url} #{observability_url} #{oauth_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 oauth url is already present in the policy' do + let(:csp) do + ActionDispatch::ContentSecurityPolicy.new do |p| + p.frame_src oauth_url + 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 append oauth again' do + expect(subject).to include( + "frame-src #{oauth_url} #{observability_url} #{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 + 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 - context 'when oauth is already present in the policy' do - let(:csp) do - ActionDispatch::ContentSecurityPolicy.new do |p| - p.frame_src oauth_url + 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 - it 'does not append oauth again' do - expect(subject).to include( - "frame-src #{oauth_url} #{observability_url} #{signin_url};") + 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 default-src exists in the CSP config' do - let(:csp) do - ActionDispatch::ContentSecurityPolicy.new do |p| - p.default_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 - end - it 'does not change default-src' do - expect(subject).to include( - "default-src https://something.test;") + 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 + + it 'does not change default-src' do + expect(subject).to include( + "default-src https://something.test;") + 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' + 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 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") + 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 + + 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 end end diff --git a/spec/uploaders/avatar_uploader_spec.rb b/spec/uploaders/avatar_uploader_spec.rb index e472ac46e66..bba7eb78f99 100644 --- a/spec/uploaders/avatar_uploader_spec.rb +++ b/spec/uploaders/avatar_uploader_spec.rb @@ -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' diff --git a/spec/uploaders/design_management/design_v432x230_uploader_spec.rb b/spec/uploaders/design_management/design_v432x230_uploader_spec.rb index f3dd77d67a0..3991058b32d 100644 --- a/spec/uploaders/design_management/design_v432x230_uploader_spec.rb +++ b/spec/uploaders/design_management/design_v432x230_uploader_spec.rb @@ -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' diff --git a/spec/uploaders/favicon_uploader_spec.rb b/spec/uploaders/favicon_uploader_spec.rb index 7f452075293..ab14397c27d 100644 --- a/spec/uploaders/favicon_uploader_spec.rb +++ b/spec/uploaders/favicon_uploader_spec.rb @@ -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') } diff --git a/spec/validators/cron_validator_spec.rb b/spec/validators/cron_validator_spec.rb index bd7fe242957..52a57f6e160 100644 --- a/spec/validators/cron_validator_spec.rb +++ b/spec/validators/cron_validator_spec.rb @@ -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 |