diff options
39 files changed, 267 insertions, 148 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ebf752d318..19948bb0118 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,9 @@ entry. ## 14.7.1 (2022-02-03) -No changes. +### Security + +See https://about.gitlab.com/releases/2022/02/03/security-release-gitlab-14-7-1-released/ ## 14.7.0 (2022-01-21) @@ -445,7 +447,9 @@ No changes. ## 14.6.4 (2022-02-03) -No changes. +### Security + +See https://about.gitlab.com/releases/2022/02/03/security-release-gitlab-14-7-1-released/ ## 14.6.3 (2022-01-18) @@ -847,7 +851,9 @@ No changes. ## 14.5.4 (2022-02-03) -No changes. +### Security + +See https://about.gitlab.com/releases/2022/02/03/security-release-gitlab-14-7-1-released/ ## 14.5.3 (2022-01-11) diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index d4cc38bf846..ef97d632961 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -87a19146fdc01d0132a278b661017705514207cf +6a00f3acce45365ac71798296667385efe8a72bc diff --git a/app/assets/javascripts/authentication/webauthn/util.js b/app/assets/javascripts/authentication/webauthn/util.js index 5f06c000afe..eeda2bfaeaf 100644 --- a/app/assets/javascripts/authentication/webauthn/util.js +++ b/app/assets/javascripts/authentication/webauthn/util.js @@ -14,31 +14,36 @@ export function isHTTPS() { export const FLOW_AUTHENTICATE = 'authenticate'; export const FLOW_REGISTER = 'register'; -// adapted from https://stackoverflow.com/a/21797381/8204697 -function base64ToBuffer(base64) { - const binaryString = window.atob(base64); - const len = binaryString.length; - const bytes = new Uint8Array(len); - for (let i = 0; i < len; i += 1) { - bytes[i] = binaryString.charCodeAt(i); - } - return bytes.buffer; -} - -// adapted from https://stackoverflow.com/a/9458996/8204697 -function bufferToBase64(buffer) { - if (typeof buffer === 'string') { - return buffer; +/** + * Converts a base64 string to an ArrayBuffer + * + * @param {String} str - A base64 encoded string + * @returns {ArrayBuffer} + */ +export const base64ToBuffer = (str) => { + const rawStr = atob(str); + const buffer = new ArrayBuffer(rawStr.length); + const arr = new Uint8Array(buffer); + for (let i = 0; i < rawStr.length; i += 1) { + arr[i] = rawStr.charCodeAt(i); } + return arr.buffer; +}; - let binary = ''; - const bytes = new Uint8Array(buffer); - const len = bytes.byteLength; - for (let i = 0; i < len; i += 1) { - binary += String.fromCharCode(bytes[i]); +/** + * Converts ArrayBuffer to a base64-encoded string + * + * @param {ArrayBuffer, String} str - + * @returns {String} - ArrayBuffer to a base64-encoded string. + * When input is a string, returns the input as-is. + */ +export const bufferToBase64 = (input) => { + if (typeof input === 'string') { + return input; } - return window.btoa(binary); -} + const arr = new Uint8Array(input); + return btoa(String.fromCharCode(...arr)); +}; /** * Returns a copy of the given object with the id property converted to buffer diff --git a/app/assets/javascripts/environments/components/deployment.vue b/app/assets/javascripts/environments/components/deployment.vue index b3a27628272..5352805ed6a 100644 --- a/app/assets/javascripts/environments/components/deployment.vue +++ b/app/assets/javascripts/environments/components/deployment.vue @@ -1,7 +1,15 @@ <script> -import { GlBadge, GlButton, GlCollapse, GlIcon, GlTooltipDirective as GlTooltip } from '@gitlab/ui'; +import { + GlBadge, + GlButton, + GlCollapse, + GlIcon, + GlLink, + GlTooltipDirective as GlTooltip, +} from '@gitlab/ui'; import { GlBreakpointInstance } from '@gitlab/ui/dist/utils'; import { __, s__ } from '~/locale'; +import { truncate } from '~/lib/utils/text_utility'; import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; import DeploymentStatusBadge from './deployment_status_badge.vue'; @@ -16,6 +24,7 @@ export default { GlButton, GlCollapse, GlIcon, + GlLink, TimeAgoTooltip, }, directives: { @@ -62,6 +71,15 @@ export default { commit() { return this.deployment?.commit; }, + user() { + return this.deployment?.user; + }, + username() { + return truncate(this.user?.username, 25); + }, + userPath() { + return this.user?.path; + }, }, methods: { toggleCollapse() { @@ -75,6 +93,7 @@ export default { commitSha: __('Commit SHA'), showDetails: __('Show details'), hideDetails: __('Hide details'), + triggerer: s__('Deployment|Triggerer'), }, headerClasses: [ 'gl-display-flex', @@ -149,6 +168,13 @@ export default { </gl-button> </div> <commit v-if="commit" :commit="commit" class="gl-mt-3" /> - <gl-collapse :visible="visible" /> + <gl-collapse :visible="visible"> + <div class="gl-display-flex gl-align-items-center gl-mt-5"> + <div v-if="user" class="gl-display-flex gl-flex-direction-column"> + <span class="gl-text-gray-500 gl-font-weight-bold">{{ $options.i18n.triggerer }}</span> + <gl-link :href="userPath" class="gl-font-monospace gl-mt-3"> @{{ username }} </gl-link> + </div> + </div> + </gl-collapse> </div> </template> diff --git a/app/assets/javascripts/environments/components/new_environment_item.vue b/app/assets/javascripts/environments/components/new_environment_item.vue index e23a02b3dfd..48a77c021bf 100644 --- a/app/assets/javascripts/environments/components/new_environment_item.vue +++ b/app/assets/javascripts/environments/components/new_environment_item.vue @@ -99,8 +99,8 @@ export default { if (!this.lastDeployment) { return []; } - const { manualActions = [], scheduledActions = [] } = this.lastDeployment; - const combinedActions = [...manualActions, ...scheduledActions]; + const { manualActions, scheduledActions } = this.lastDeployment; + const combinedActions = [...(manualActions ?? []), ...(scheduledActions ?? [])]; return combinedActions.map((action) => ({ ...action, })); diff --git a/app/assets/javascripts/runner/components/runner_list.vue b/app/assets/javascripts/runner/components/runner_list.vue index 023308dbac2..50fb8d36992 100644 --- a/app/assets/javascripts/runner/components/runner_list.vue +++ b/app/assets/javascripts/runner/components/runner_list.vue @@ -70,9 +70,9 @@ export default { }, fields: [ tableField({ key: 'status', label: s__('Runners|Status') }), - tableField({ key: 'summary', label: s__('Runners|Runner ID'), thClasses: ['gl-lg-w-25p'] }), + tableField({ key: 'summary', label: s__('Runners|Runner'), thClasses: ['gl-lg-w-25p'] }), tableField({ key: 'version', label: __('Version') }), - tableField({ key: 'ipAddress', label: __('IP Address') }), + tableField({ key: 'ipAddress', label: __('IP') }), tableField({ key: 'jobCount', label: __('Jobs') }), tableField({ key: 'tagList', label: __('Tags'), thClasses: ['gl-lg-w-25p'] }), tableField({ key: 'contactedAt', label: __('Last contact') }), diff --git a/app/graphql/types/project_type.rb b/app/graphql/types/project_type.rb index fd402f488e0..dc428e7bdce 100644 --- a/app/graphql/types/project_type.rb +++ b/app/graphql/types/project_type.rb @@ -15,6 +15,8 @@ module Types description: 'Full path of the project.' field :path, GraphQL::Types::String, null: false, description: 'Path of the project.' + field :ci_config_path_or_default, GraphQL::Types::String, null: false, + description: 'Path of the CI configuration file.' field :sast_ci_configuration, Types::CiConfiguration::Sast::Type, null: true, calls_gitaly: true, diff --git a/app/helpers/invite_members_helper.rb b/app/helpers/invite_members_helper.rb index 19a23550268..49f1dd76e96 100644 --- a/app/helpers/invite_members_helper.rb +++ b/app/helpers/invite_members_helper.rb @@ -6,7 +6,7 @@ module InviteMembersHelper def can_invite_members_for_project?(project) # do not use the can_admin_project_member? helper here due to structure of the view and how membership_locked? # is leveraged for inviting groups - Feature.enabled?(:invite_members_group_modal, project.group) && can?(current_user, :admin_project_member, project) + Feature.enabled?(:invite_members_group_modal, project.group, default_enabled: :yaml) && can?(current_user, :admin_project_member, project) end def invite_accepted_notice(member) diff --git a/app/models/integration.rb b/app/models/integration.rb index 89b34932e20..e9cd90649ba 100644 --- a/app/models/integration.rb +++ b/app/models/integration.rb @@ -392,8 +392,7 @@ class Integration < ApplicationRecord end def api_field_names - fields.map { |field| field[:name] } - .reject { |field_name| field_name =~ /(password|token|key|title|description)/ } + fields.pluck(:name).grep_v(/password|token|key|title|description/) end def global_fields diff --git a/app/services/merge_requests/after_create_service.rb b/app/services/merge_requests/after_create_service.rb index 83525899e98..93a0d375b97 100644 --- a/app/services/merge_requests/after_create_service.rb +++ b/app/services/merge_requests/after_create_service.rb @@ -5,9 +5,8 @@ module MergeRequests include Gitlab::Utils::StrongMemoize def execute(merge_request) - prepare_for_mergeability(merge_request) if early_prepare_for_mergeability?(merge_request) + prepare_for_mergeability(merge_request) prepare_merge_request(merge_request) - check_mergeability(merge_request) unless early_prepare_for_mergeability?(merge_request) end private @@ -26,11 +25,6 @@ module MergeRequests notification_service.new_merge_request(merge_request, current_user) - unless early_prepare_for_mergeability?(merge_request) - create_pipeline_for(merge_request, current_user) - merge_request.update_head_pipeline - end - merge_request.diffs(include_stats: false).write_cache merge_request.create_cross_references!(current_user) @@ -49,12 +43,6 @@ module MergeRequests LinkLfsObjectsService.new(project: merge_request.target_project).execute(merge_request) end - def early_prepare_for_mergeability?(merge_request) - strong_memoize("early_prepare_for_mergeability_#{merge_request.target_project_id}".to_sym) do - Feature.enabled?(:early_prepare_for_mergeability, merge_request.target_project) - end - end - def check_mergeability(merge_request) return unless merge_request.preparing? diff --git a/app/services/quick_actions/interpret_service.rb b/app/services/quick_actions/interpret_service.rb index ab489ba49ca..68723097de3 100644 --- a/app/services/quick_actions/interpret_service.rb +++ b/app/services/quick_actions/interpret_service.rb @@ -61,6 +61,10 @@ module QuickActions private + def failed_parse(message) + raise Gitlab::QuickActions::CommandDefinition::ParseError, message + end + def extractor Gitlab::QuickActions::Extractor.new(self.class.command_definitions) end @@ -69,6 +73,7 @@ module QuickActions def extract_users(params) return [] if params.nil? + args = params.split(' ').uniq users = extract_references(params, :user) if users.empty? @@ -76,10 +81,12 @@ module QuickActions if params.strip == 'me' [current_user] else - User.where(username: params.split(' ').map(&:strip)) + User.where(username: args) end end + failed_parse(format(_("Failed to find users for '%{params}'"), params: params)) unless users.size == args.size + users end # rubocop: enable CodeReuse/ActiveRecord diff --git a/app/views/groups/group_members/index.html.haml b/app/views/groups/group_members/index.html.haml index 97867e312af..e751a650412 100644 --- a/app/views/groups/group_members/index.html.haml +++ b/app/views/groups/group_members/index.html.haml @@ -11,7 +11,7 @@ = _('Group members') %p = html_escape(_('You can invite a new member to %{strong_start}%{group_name}%{strong_end}.')) % { group_name: @group.name, strong_start: '<strong>'.html_safe, strong_end: '</strong>'.html_safe } - - if Feature.enabled?(:invite_members_group_modal, @group) + - if Feature.enabled?(:invite_members_group_modal, @group, default_enabled: :yaml) .gl-w-half.gl-xs-w-full .gl-display-flex.gl-flex-wrap.gl-justify-content-end.gl-mb-3 .js-invite-group-trigger{ data: { classes: 'gl-mt-3 gl-sm-w-auto gl-w-full', display_text: _('Invite a group') } } @@ -20,7 +20,7 @@ trigger_source: 'group-members-page', display_text: _('Invite members') } } = render 'groups/invite_members_modal', group: @group - - if can_admin_group_member?(@group) && Feature.disabled?(:invite_members_group_modal, @group) + - if can_admin_group_member?(@group) && Feature.disabled?(:invite_members_group_modal, @group, default_enabled: :yaml) %hr.gl-mt-4 %ul.nav-links.nav.nav-tabs.gitlab-tabs{ role: 'tablist' } %li.nav-tab{ role: 'presentation' } diff --git a/app/views/projects/project_members/index.html.haml b/app/views/projects/project_members/index.html.haml index f2a9b46321c..4a25bda3281 100644 --- a/app/views/projects/project_members/index.html.haml +++ b/app/views/projects/project_members/index.html.haml @@ -38,7 +38,7 @@ %p = html_escape(_("Members can be added by project %{i_open}Maintainers%{i_close} or %{i_open}Owners%{i_close}")) % { i_open: '<i>'.html_safe, i_close: '</i>'.html_safe } - - if Feature.disabled?(:invite_members_group_modal, @project.group) && can?(current_user, :admin_project_member, @project) && project_can_be_shared? + - if Feature.disabled?(:invite_members_group_modal, @project.group, default_enabled: :yaml) && can?(current_user, :admin_project_member, @project) && project_can_be_shared? - if !membership_locked? && @project.allowed_to_share_with_group? %ul.nav-links.nav.nav-tabs.gitlab-tabs{ role: 'tablist' } %li.nav-tab{ role: 'presentation' } diff --git a/app/views/projects/settings/_general.html.haml b/app/views/projects/settings/_general.html.haml index 69c3f9ca286..960b1d67610 100644 --- a/app/views/projects/settings/_general.html.haml +++ b/app/views/projects/settings/_general.html.haml @@ -37,6 +37,6 @@ = render 'shared/choose_avatar_button', f: f - if @project.avatar? %hr - = link_to _('Remove avatar'), project_avatar_path(@project), data: { confirm: _('Avatar will be removed. Are you sure?')}, method: :delete, class: 'gl-button btn btn-danger-secondary' + = link_to _('Remove avatar'), project_avatar_path(@project), aria: { label: _('Remove avatar') }, data: { confirm: _('Avatar will be removed. Are you sure?'), 'confirm-btn-variant': 'danger' }, method: :delete, class: 'gl-button btn btn-danger-secondary' = f.submit _('Save changes'), class: "gl-button btn btn-confirm gl-mt-6", data: { qa_selector: 'save_naming_topics_avatar_button' } diff --git a/config/feature_flags/development/bulk_expire_project_artifacts.yml b/config/feature_flags/development/bulk_expire_project_artifacts.yml index 609f87847fa..9f1949e3dd2 100644 --- a/config/feature_flags/development/bulk_expire_project_artifacts.yml +++ b/config/feature_flags/development/bulk_expire_project_artifacts.yml @@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75488 rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/347405 milestone: '14.6' type: development -group: group::testing +group: group::pipeline insights default_enabled: true diff --git a/config/feature_flags/development/ci_destroy_unlocked_job_artifacts.yml b/config/feature_flags/development/ci_destroy_unlocked_job_artifacts.yml index b064e6bf09f..dd7192f0bc8 100644 --- a/config/feature_flags/development/ci_destroy_unlocked_job_artifacts.yml +++ b/config/feature_flags/development/ci_destroy_unlocked_job_artifacts.yml @@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/72406 rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/338165 milestone: '14.5' type: development -group: group::testing +group: group::pipeline insights default_enabled: false diff --git a/config/feature_flags/development/ci_update_unlocked_job_artifacts.yml b/config/feature_flags/development/ci_update_unlocked_job_artifacts.yml index 9157928f352..f756de86efb 100644 --- a/config/feature_flags/development/ci_update_unlocked_job_artifacts.yml +++ b/config/feature_flags/development/ci_update_unlocked_job_artifacts.yml @@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/70235 rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/343465 milestone: '14.5' type: development -group: group::testing +group: group::pipeline insights default_enabled: false diff --git a/config/feature_flags/development/early_prepare_for_mergeability.yml b/config/feature_flags/development/early_prepare_for_mergeability.yml deleted file mode 100644 index c6377bd9a60..00000000000 --- a/config/feature_flags/development/early_prepare_for_mergeability.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: early_prepare_for_mergeability -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75402 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/346667 -milestone: '14.6' -type: development -group: group::code review -default_enabled: false diff --git a/config/feature_flags/development/invite_members_group_modal.yml b/config/feature_flags/development/invite_members_group_modal.yml index 444cc79ff57..ab28a2c6e24 100644 --- a/config/feature_flags/development/invite_members_group_modal.yml +++ b/config/feature_flags/development/invite_members_group_modal.yml @@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/247208 milestone: '13.5' type: development group: group::expansion -default_enabled: false +default_enabled: true diff --git a/config/feature_flags/development/notes_create_service_tracking.yml b/config/feature_flags/development/notes_create_service_tracking.yml index 5601088b25f..578c1e2a707 100644 --- a/config/feature_flags/development/notes_create_service_tracking.yml +++ b/config/feature_flags/development/notes_create_service_tracking.yml @@ -1,8 +1,8 @@ --- name: notes_create_service_tracking introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/18890 -rollout_issue_url: +rollout_issue_url: milestone: '12.5' type: development -group: group::testing +group: group::pipeline insights default_enabled: false diff --git a/config/feature_flags/development/s3_multithreaded_uploads.yml b/config/feature_flags/development/s3_multithreaded_uploads.yml index f80510a4c64..6c3ecac4143 100644 --- a/config/feature_flags/development/s3_multithreaded_uploads.yml +++ b/config/feature_flags/development/s3_multithreaded_uploads.yml @@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/50922 rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/296772 milestone: '13.8' type: development -group: group::testing +group: group::pipeline insights default_enabled: true diff --git a/data/deprecations/14-8-geo-deprecate-replication-detail-routes.yml b/data/deprecations/14-8-geo-deprecate-replication-detail-routes.yml new file mode 100644 index 00000000000..94a026edd81 --- /dev/null +++ b/data/deprecations/14-8-geo-deprecate-replication-detail-routes.yml @@ -0,0 +1,15 @@ +- name: "Deprecate Geo Admin UI Routes" + announcement_milestone: "14.8" + announcement_date: "2022-02-22" + removal_milestone: "15.0" + removal_date: "2022-05-22" + breaking_change: false + reporter: nhxnguyen + body: | + In GitLab 13.0, we introduced new project and design replication details routes in the Geo Admin UI. These routes are `/admin/geo/replication/projects` and `/admin/geo/replication/designs`. We kept the legacy routes and redirected them to the new routes. In GitLab 15.0, we will remove support for the legacy routes `/admin/geo/projects` and `/admin/geo/designs`. Please update any bookmarks or scripts that may use the legacy routes. + stage: "Enablement" + tiers: ["Premium", "Ultimate"] + issue_url: "https://gitlab.com/gitlab-org/gitlab/-/issues/351345" + documentation_url: # (optional) This is a link to the current documentation page + image_url: # (optional) This is a link to a thumbnail image depicting the feature + video_url: # (optional) Use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index d7b878fb1a9..28b7a67ad34 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -13433,6 +13433,7 @@ Represents vulnerability finding of a security report on the pipeline. | <a id="projectautoclosereferencedissues"></a>`autocloseReferencedIssues` | [`Boolean`](#boolean) | Indicates if issues referenced by merge requests and commits within the default branch are closed automatically. | | <a id="projectavatarurl"></a>`avatarUrl` | [`String`](#string) | URL to avatar image file of the project. | | <a id="projectcicdsettings"></a>`ciCdSettings` | [`ProjectCiCdSetting`](#projectcicdsetting) | CI/CD settings for the project. | +| <a id="projectciconfigpathordefault"></a>`ciConfigPathOrDefault` | [`String!`](#string) | Path of the CI configuration file. | | <a id="projectcijobtokenscope"></a>`ciJobTokenScope` | [`CiJobTokenScopeType`](#cijobtokenscopetype) | The CI Job Tokens scope of access. | | <a id="projectclusteragents"></a>`clusterAgents` | [`ClusterAgentConnection`](#clusteragentconnection) | Cluster agents associated with the project. (see [Connections](#connections)) | | <a id="projectcodecoveragesummary"></a>`codeCoverageSummary` | [`CodeCoverageSummary`](#codecoveragesummary) | Code coverage summary associated with the project. | diff --git a/doc/update/deprecations.md b/doc/update/deprecations.md index 77a6311f3c2..4284ec93d03 100644 --- a/doc/update/deprecations.md +++ b/doc/update/deprecations.md @@ -727,6 +727,12 @@ The `merged_by` field in the [merge request API](https://docs.gitlab.com/ee/api/ ## 14.8 +### Deprecate Geo Admin UI Routes + +In GitLab 13.0, we introduced new project and design replication details routes in the Geo Admin UI. These routes are `/admin/geo/replication/projects` and `/admin/geo/replication/designs`. We kept the legacy routes and redirected them to the new routes. In GitLab 15.0, we will remove support for the legacy routes `/admin/geo/projects` and `/admin/geo/designs`. Please update any bookmarks or scripts that may use the legacy routes. + +**Planned removal milestone: 15.0 (2022-05-22)** + ### External status check API breaking changes WARNING: diff --git a/doc/user/project/members/index.md b/doc/user/project/members/index.md index 3132bd9a961..9b2c61a5b4c 100644 --- a/doc/user/project/members/index.md +++ b/doc/user/project/members/index.md @@ -206,15 +206,14 @@ Instead of adding users one by one, you can [share a project with an entire grou ### Add a member modal window -> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/247208) in GitLab 13.11. -> - [Deployed behind a feature flag](../../feature_flags.md), disabled by default. -> - Enabled on GitLab.com. -> - Recommended for production use. +> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/247208) in GitLab 13.11 [with a flag](../../feature_flags.md). Disabled by default. > - Replaces the existing form with buttons to open a modal window. -> - To use in GitLab self-managed instances, ask a GitLab administrator to [enable it](#enable-or-disable-modal-window). +> - [Enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/247208) in GitLab 14.8. -WARNING: -This feature might not be available to you. Check the **version history** note above for details. +FLAG: +On self-managed GitLab, by default this feature is available. +To hide the feature, ask an administrator to [disable the feature flag](#enable-or-disable-modal-window). +On GitLab.com, this feature is available. In GitLab 13.11, you can optionally replace the form to add a member with a modal window. To add a member after enabling this feature: @@ -229,7 +228,7 @@ To add a member after enabling this feature: ### Enable or disable modal window **(FREE SELF)** The modal window for adding a member is under development and is ready for production use. It is -deployed behind a feature flag that is **disabled by default**. +deployed behind a feature flag that is **enabled by default**. [GitLab administrators with access to the GitLab Rails console](../../../administration/feature_flags.md) can enable it. diff --git a/lib/gitlab/ci/templates/Jobs/SAST.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/SAST.gitlab-ci.yml index 37a746a223c..05f76653bc8 100644 --- a/lib/gitlab/ci/templates/Jobs/SAST.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Jobs/SAST.gitlab-ci.yml @@ -221,14 +221,23 @@ security-code-scan-sast: image: name: "$SAST_ANALYZER_IMAGE" variables: - SAST_ANALYZER_IMAGE_TAG: 2 SAST_ANALYZER_IMAGE: "$SECURE_ANALYZERS_PREFIX/security-code-scan:$SAST_ANALYZER_IMAGE_TAG" rules: - if: $SAST_DISABLED when: never - if: $SAST_EXCLUDED_ANALYZERS =~ /security-code-scan/ when: never + # This rule shim will be removed in %15.0, + # See https://gitlab.com/gitlab-org/gitlab/-/issues/350935 + - if: $CI_COMMIT_BRANCH && $CI_SERVER_VERSION_MAJOR == '14' + variables: + SAST_ANALYZER_IMAGE_TAG: '2' + exists: + - '**/*.csproj' + - '**/*.vbproj' - if: $CI_COMMIT_BRANCH + variables: + SAST_ANALYZER_IMAGE_TAG: '3' exists: - '**/*.csproj' - '**/*.vbproj' diff --git a/lib/gitlab/ci/templates/Security/Secure-Binaries.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/Secure-Binaries.gitlab-ci.yml index 86b7d57d3cb..82c7bfd0620 100644 --- a/lib/gitlab/ci/templates/Security/Secure-Binaries.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Security/Secure-Binaries.gitlab-ci.yml @@ -109,6 +109,8 @@ phpcs-security-audit: security-code-scan: extends: .download_images + variables: + SECURE_BINARIES_ANALYZER_VERSION: "3" only: variables: - $SECURE_BINARIES_DOWNLOAD_IMAGES == "true" && diff --git a/lib/gitlab/quick_actions/command_definition.rb b/lib/gitlab/quick_actions/command_definition.rb index 8ce13db4c03..fcb7bc967ca 100644 --- a/lib/gitlab/quick_actions/command_definition.rb +++ b/lib/gitlab/quick_actions/command_definition.rb @@ -3,6 +3,8 @@ module Gitlab module QuickActions class CommandDefinition + ParseError = Class.new(StandardError) + attr_accessor :name, :aliases, :description, :explanation, :execution_message, :params, :condition_block, :parse_params_block, :action_block, :warning, :icon, :types @@ -41,7 +43,11 @@ module Gitlab return unless available?(context) message = if explanation.respond_to?(:call) - execute_block(explanation, context, arg) + begin + execute_block(explanation, context, arg) + rescue ParseError => e + format(_('Problem with %{name} command: %{message}.'), name: name, message: e.message) + end else explanation end @@ -63,6 +69,8 @@ module Gitlab return unless available?(context) execute_block(action_block, context, arg) + rescue ParseError + # message propagation is handled in `execution_message`. end def execute_message(context, arg) @@ -74,6 +82,8 @@ module Gitlab else execution_message end + rescue ParseError => e + format _('Could not apply %{name} command. %{message}.'), name: name, message: e.message end def to_h(context) diff --git a/lib/gitlab/quick_actions/merge_request_actions.rb b/lib/gitlab/quick_actions/merge_request_actions.rb index cc2021e14e3..03f5ffd37ae 100644 --- a/lib/gitlab/quick_actions/merge_request_actions.rb +++ b/lib/gitlab/quick_actions/merge_request_actions.rb @@ -184,7 +184,7 @@ module Gitlab execution_message do |users = nil| reviewers = reviewers_to_add(users) if reviewers.blank? - _("Failed to assign a reviewer because no user was found.") + _("Failed to assign a reviewer because no user was specified.") else _('Assigned %{reviewer_users_sentence} as %{reviewer_text}.') % { reviewer_users_sentence: reviewer_users_sentence(users), reviewer_text: 'reviewer'.pluralize(reviewers.size) } diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 0f766d48a35..5c4461f8801 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -9953,6 +9953,9 @@ msgstr "" msgid "Could not apply %{name} command." msgstr "" +msgid "Could not apply %{name} command. %{message}." +msgstr "" + msgid "Could not authorize chat nickname. Try again!" msgstr "" @@ -12148,6 +12151,9 @@ msgstr "" msgid "Deployment|This deployment was created using the API" msgstr "" +msgid "Deployment|Triggerer" +msgstr "" + msgid "Deployment|Waiting" msgstr "" @@ -12740,6 +12746,9 @@ msgid_plural "Dismiss %d selected vulnerabilities as" msgstr[0] "" msgstr[1] "" +msgid "Dismiss Alert" +msgstr "" + msgid "Dismiss merge request promotion" msgstr "" @@ -14783,7 +14792,7 @@ msgid_plural "Failed to archive designs. Please try again." msgstr[0] "" msgstr[1] "" -msgid "Failed to assign a reviewer because no user was found." +msgid "Failed to assign a reviewer because no user was specified." msgstr "" msgid "Failed to assign a user because no user was found." @@ -14849,6 +14858,9 @@ msgstr "" msgid "Failed to find import label for Jira import." msgstr "" +msgid "Failed to find users for '%{params}'" +msgstr "" + msgid "Failed to generate export, please try again later." msgstr "" @@ -18071,6 +18083,9 @@ msgstr "" msgid "INFO: Your SSH key is expiring soon. Please generate a new key." msgstr "" +msgid "IP" +msgstr "" + msgid "IP Address" msgstr "" @@ -27321,6 +27336,9 @@ msgstr "" msgid "Private projects can be created in your personal namespace with:" msgstr "" +msgid "Problem with %{name} command: %{message}." +msgstr "" + msgid "Proceed" msgstr "" @@ -31177,9 +31195,6 @@ msgstr "" msgid "Runners|Runner %{name} was deleted" msgstr "" -msgid "Runners|Runner ID" -msgstr "" - msgid "Runners|Runner assigned to project." msgstr "" @@ -31976,6 +31991,9 @@ msgstr "" msgid "SecurityOrchestration|Add rule" msgstr "" +msgid "SecurityOrchestration|After dismissing the alert, the information will never be shown again." +msgstr "" + msgid "SecurityOrchestration|All policies" msgstr "" @@ -31991,6 +32009,9 @@ msgstr "" msgid "SecurityOrchestration|Description" msgstr "" +msgid "SecurityOrchestration|Don't show the alert anymore" +msgstr "" + msgid "SecurityOrchestration|Edit policy" msgstr "" @@ -32015,6 +32036,9 @@ msgstr "" msgid "SecurityOrchestration|Latest scan" msgstr "" +msgid "SecurityOrchestration|Latest scan run against %{agent}" +msgstr "" + msgid "SecurityOrchestration|Network" msgstr "" @@ -32120,6 +32144,9 @@ msgstr "" msgid "SecurityOrchestration|This project does not contain any security policies." msgstr "" +msgid "SecurityOrchestration|This view only shows scan results for the agent %{agent}. You can view scan results for all agents in the %{linkStart}Operational Vulnerabilities tab of the vulnerability report%{linkEnd}." +msgstr "" + msgid "SecurityOrchestration|To widen your search, change filters above or select a different security policy project." msgstr "" diff --git a/package.json b/package.json index d4161674fca..db9337805e1 100644 --- a/package.json +++ b/package.json @@ -55,8 +55,8 @@ "@babel/preset-env": "^7.10.1", "@gitlab/at.js": "1.5.7", "@gitlab/favicon-overlay": "2.0.0", - "@gitlab/svgs": "2.2.0", - "@gitlab/ui": "35.0.0", + "@gitlab/svgs": "2.3.0", + "@gitlab/ui": "35.1.0", "@gitlab/visual-review-tools": "1.6.1", "@rails/actioncable": "6.1.4-1", "@rails/ujs": "6.1.4-1", diff --git a/spec/frontend/authentication/webauthn/util_spec.js b/spec/frontend/authentication/webauthn/util_spec.js new file mode 100644 index 00000000000..c9b8bfd8679 --- /dev/null +++ b/spec/frontend/authentication/webauthn/util_spec.js @@ -0,0 +1,19 @@ +import { base64ToBuffer, bufferToBase64 } from '~/authentication/webauthn/util'; + +const encodedString = 'SGVsbG8gd29ybGQh'; +const stringBytes = [72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33]; + +describe('Webauthn utils', () => { + it('base64ToBuffer', () => { + const toArray = (val) => new Uint8Array(val); + + expect(base64ToBuffer(encodedString)).toBeInstanceOf(ArrayBuffer); + + expect(toArray(base64ToBuffer(encodedString))).toEqual(toArray(stringBytes)); + }); + + it('bufferToBase64', () => { + const buffer = base64ToBuffer(encodedString); + expect(bufferToBase64(buffer)).toBe(encodedString); + }); +}); diff --git a/spec/frontend/environments/deployment_spec.js b/spec/frontend/environments/deployment_spec.js index 992bffd6e3f..6ce0b76d98e 100644 --- a/spec/frontend/environments/deployment_spec.js +++ b/spec/frontend/environments/deployment_spec.js @@ -149,7 +149,7 @@ describe('~/environments/components/deployment.vue', () => { }); describe('is not present', () => { it('does not show the timestamp', () => { - wrapper = createWrapper({ propsData: { deployment: { createdAt: null } } }); + wrapper = createWrapper({ propsData: { deployment: { ...deployment, createdAt: null } } }); const date = wrapper.findByTitle(formatDate(deployment.createdAt)); expect(date.exists()).toBe(false); @@ -205,6 +205,10 @@ describe('~/environments/components/deployment.vue', () => { expect(button.text()).toBe(__('Hide details')); expect(button.props('icon')).toBe('expand-up'); expect(collapse.attributes('visible')).toBe('visible'); + + const username = wrapper.findByRole('link', { name: `@${deployment.user.username}` }); + + expect(username.attributes('href')).toBe(deployment.user.path); }); }); }); diff --git a/spec/frontend/runner/components/runner_list_spec.js b/spec/frontend/runner/components/runner_list_spec.js index c50486b6f7b..42d6ecca09e 100644 --- a/spec/frontend/runner/components/runner_list_spec.js +++ b/spec/frontend/runner/components/runner_list_spec.js @@ -46,9 +46,9 @@ describe('RunnerList', () => { expect(headerLabels).toEqual([ 'Status', - 'Runner ID', + 'Runner', 'Version', - 'IP Address', + 'IP', 'Jobs', 'Tags', 'Last contact', diff --git a/spec/graphql/types/project_type_spec.rb b/spec/graphql/types/project_type_spec.rb index 6ade44b54d1..7433d465b38 100644 --- a/spec/graphql/types/project_type_spec.rb +++ b/spec/graphql/types/project_type_spec.rb @@ -35,7 +35,7 @@ RSpec.describe GitlabSchema.types['Project'] do pipeline_analytics squash_read_only sast_ci_configuration cluster_agent cluster_agents agent_configurations ci_template timelogs merge_commit_template squash_commit_template work_item_types - recent_issue_boards + recent_issue_boards ci_config_path_or_default ] expect(described_class).to include_graphql_fields(*expected_fields) diff --git a/spec/models/integration_spec.rb b/spec/models/integration_spec.rb index 7bc670302f1..e822620ab80 100644 --- a/spec/models/integration_spec.rb +++ b/spec/models/integration_spec.rb @@ -710,30 +710,21 @@ RSpec.describe Integration do [ { name: 'token' }, { name: 'api_token' }, + { name: 'token_api' }, + { name: 'safe_token' }, { name: 'key' }, { name: 'api_key' }, { name: 'password' }, { name: 'password_field' }, + { name: 'some_safe_field' }, { name: 'safe_field' } - ] + ].shuffle end end end - let(:integration) do - fake_integration.new(properties: [ - { token: 'token-value' }, - { api_token: 'api_token-value' }, - { key: 'key-value' }, - { api_key: 'api_key-value' }, - { password: 'password-value' }, - { password_field: 'password_field-value' }, - { safe_field: 'safe_field-value' } - ]) - end - it 'filters out sensitive fields' do - expect(integration.api_field_names).to eq(['safe_field']) + expect(fake_integration.new).to have_attributes(api_field_names: match_array(%w[some_safe_field safe_field])) end end diff --git a/spec/services/merge_requests/after_create_service_spec.rb b/spec/services/merge_requests/after_create_service_spec.rb index ff6ccc75244..2155b4ffad1 100644 --- a/spec/services/merge_requests/after_create_service_spec.rb +++ b/spec/services/merge_requests/after_create_service_spec.rb @@ -108,17 +108,6 @@ RSpec.describe MergeRequests::AfterCreateService do expect { execute_service }.to raise_error(StandardError) expect(merge_request.reload).to be_preparing end - - context 'when early_prepare_for_mergeability feature flag is disabled' do - before do - stub_feature_flags(early_prepare_for_mergeability: false) - end - - it 'does not mark the merge request as unchecked' do - expect { execute_service }.to raise_error(StandardError) - expect(merge_request.reload).to be_preparing - end - end end context 'when preparing merge request fails' do @@ -134,17 +123,6 @@ RSpec.describe MergeRequests::AfterCreateService do expect(merge_request).to receive(:check_mergeability).with(async: true) expect { execute_service }.to raise_error(StandardError) end - - context 'when early_prepare_for_mergeability feature flag is disabled' do - before do - stub_feature_flags(early_prepare_for_mergeability: false) - end - - it 'does not mark the merge request as unchecked' do - expect { execute_service }.to raise_error(StandardError) - expect(merge_request.reload).to be_preparing - end - end end end diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb index 2c84702a526..e3a6a60393d 100644 --- a/spec/services/quick_actions/interpret_service_spec.rb +++ b/spec/services/quick_actions/interpret_service_spec.rb @@ -485,6 +485,8 @@ RSpec.describe QuickActions::InterpretService do end shared_examples 'failed command' do |error_msg| + let(:match_msg) { error_msg ? eq(error_msg) : be_empty } + it 'populates {} if content contains an unsupported command' do _, updates, _ = service.execute(content, issuable) @@ -494,11 +496,7 @@ RSpec.describe QuickActions::InterpretService do it "returns #{error_msg || 'an empty'} message" do _, _, message = service.execute(content, issuable) - if error_msg - expect(message).to eq(error_msg) - else - expect(message).to be_empty - end + expect(message).to match_msg end end @@ -887,9 +885,10 @@ RSpec.describe QuickActions::InterpretService do end end - it_behaves_like 'failed command', "Failed to assign a user because no user was found." do + it_behaves_like 'failed command', 'a parse error' do let(:content) { '/assign @abcd1234' } let(:issuable) { issue } + let(:match_msg) { eq "Could not apply assign command. Failed to find users for '@abcd1234'." } end it_behaves_like 'failed command', "Failed to assign a user because no user was found." do @@ -953,7 +952,9 @@ RSpec.describe QuickActions::InterpretService do context 'with an incorrect user' do let(:content) { '/assign_reviewer @abcd1234' } - it_behaves_like 'failed command', "Failed to assign a reviewer because no user was found." + it_behaves_like 'failed command', 'a parse error' do + let(:match_msg) { eq "Could not apply assign_reviewer command. Failed to find users for '@abcd1234'." } + end end context 'with the "reviewer" alias' do @@ -971,13 +972,16 @@ RSpec.describe QuickActions::InterpretService do context 'with no user' do let(:content) { '/assign_reviewer' } - it_behaves_like 'failed command', "Failed to assign a reviewer because no user was found." + it_behaves_like 'failed command', "Failed to assign a reviewer because no user was specified." end - context 'includes only the user reference with extra text' do - let(:content) { "/assign_reviewer @#{developer.username} do it!" } + context 'with extra text' do + let(:arg) { "@#{developer.username} do it!" } + let(:content) { "/assign_reviewer #{arg}" } - it_behaves_like 'assign_reviewer command' + it_behaves_like 'failed command', 'a parse error' do + let(:match_msg) { eq "Could not apply assign_reviewer command. Failed to find users for '#{arg}'." } + end end end @@ -2317,12 +2321,41 @@ RSpec.describe QuickActions::InterpretService do end describe 'assign command' do - let(:content) { "/assign @#{developer.username} do it!" } + shared_examples 'assigns developer' do + it 'tells us we will assign the developer' do + _, explanations = service.explain(content, merge_request) - it 'includes only the user reference' do - _, explanations = service.explain(content, merge_request) + expect(explanations).to eq(["Assigns @#{developer.username}."]) + end + end + + context 'when using a reference' do + let(:content) { "/assign @#{developer.username}" } + + include_examples 'assigns developer' + end + + context 'when using a bare username' do + let(:content) { "/assign #{developer.username}" } + + include_examples 'assigns developer' + end - expect(explanations).to eq(["Assigns @#{developer.username}."]) + context 'when using me' do + let(:content) { "/assign me" } + + include_examples 'assigns developer' + end + + context 'when there are unparseable arguments' do + let(:arg) { "#{developer.username} to this issue" } + let(:content) { "/assign #{arg}" } + + it 'tells us why we cannot do that' do + _, explanations = service.explain(content, merge_request) + + expect(explanations).to eq ["Problem with assign command: Failed to find users for '#{arg}'."] + end end end diff --git a/yarn.lock b/yarn.lock index 02011b7d89d..48ecc06f3e2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -957,15 +957,15 @@ stylelint-declaration-strict-value "1.8.0" stylelint-scss "4.1.0" -"@gitlab/svgs@2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-2.2.0.tgz#95cf58d6ae634d535145159f08f5cff6241d4013" - integrity sha512-mCwR3KfNPsxRoojtTjMIZwdd4FFlBh5DlR9AeodP+7+k8rILdWGYxTZbJMPNXoPbZx16R94nG8c5bR7toD4QBw== +"@gitlab/svgs@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-2.3.0.tgz#2ddb38c1e27a5f1945863c3093107117c0175be4" + integrity sha512-VXryDplnM+sImEleyxDnW4oyDvIwUhSCZ/+hxYmXesysQiK+vm+hEfdc2N+AnlD2xbdbnuMQnegckOL38Ic2/g== -"@gitlab/ui@35.0.0": - version "35.0.0" - resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-35.0.0.tgz#9fb89babddc337830f1245044fe7946b266395b4" - integrity sha512-iGGsLFgy/BOnmym2VBT+ByiP7mY/DtJPDSoYjd7QtJbOF17A+MyvOwBFGTUXAJxDtWTYSkMZkEuwZVA3VOEwyQ== +"@gitlab/ui@35.1.0": + version "35.1.0" + resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-35.1.0.tgz#feebe3e7bc4260b256c92e753201f12dae3d8857" + integrity sha512-j0+kXYkWfgxrHUG41WR0xL+ctcPwGhCM2YxinKy0DQmXmHGgw380bk922/r2yXAnQ6A4KDuvjQz1Ue0m1Yj6Cw== dependencies: "@babel/standalone" "^7.0.0" bootstrap-vue "2.20.1" |