Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.rubocop_todo/layout/line_length.yml1
-rw-r--r--.rubocop_todo/style/if_unless_modifier.yml1
-rw-r--r--app/assets/javascripts/groups/components/group_folder.vue2
-rw-r--r--app/assets/javascripts/groups/components/group_item.vue4
-rw-r--r--app/assets/javascripts/groups/components/groups.vue7
-rw-r--r--app/assets/javascripts/groups/components/item_caret.vue2
-rw-r--r--app/assets/javascripts/groups/components/item_type_icon.vue4
-rw-r--r--app/assets/stylesheets/pages/groups.scss47
-rw-r--r--app/models/issue.rb3
-rw-r--r--app/services/merge_requests/build_service.rb2
-rw-r--r--config/feature_flags/development/closed_as_duplicate_of_issues_api.yml (renamed from config/feature_flags/development/mr_default_description_from_repo.yml)10
-rw-r--r--config/initializers/fips.rb3
-rw-r--r--doc/api/issues.md31
-rw-r--r--doc/development/testing_guide/best_practices.md2
-rw-r--r--doc/development/testing_guide/testing_levels.md1
-rw-r--r--doc/user/application_security/index.md7
-rw-r--r--lib/api/entities/issue.rb10
-rw-r--r--lib/gitlab/fips.rb17
-rw-r--r--locale/gitlab.pot9
-rw-r--r--qa/qa/resource/api_fabricator.rb2
-rwxr-xr-xscripts/verify-tff-mapping4
-rw-r--r--spec/factories/issues.rb7
-rw-r--r--spec/lib/gitlab/fips_spec.rb47
-rw-r--r--spec/models/factories_spec.rb (renamed from spec/factories_spec.rb)4
-rw-r--r--spec/requests/api/issues/issues_spec.rb65
-rw-r--r--spec/services/merge_requests/build_service_spec.rb110
-rw-r--r--spec/tooling/lib/tooling/test_map_generator_spec.rb14
-rw-r--r--tests.yml2
-rw-r--r--tooling/quality/test_level.rb6
29 files changed, 235 insertions, 189 deletions
diff --git a/.rubocop_todo/layout/line_length.yml b/.rubocop_todo/layout/line_length.yml
index 7a60f962b4a..6d6d9f40723 100644
--- a/.rubocop_todo/layout/line_length.yml
+++ b/.rubocop_todo/layout/line_length.yml
@@ -4237,7 +4237,6 @@ Layout/LineLength:
- 'spec/factories/project_members.rb'
- 'spec/factories/projects.rb'
- 'spec/factories/usage_data.rb'
- - 'spec/factories_spec.rb'
- 'spec/features/action_cable_logging_spec.rb'
- 'spec/features/admin/admin_abuse_reports_spec.rb'
- 'spec/features/admin/admin_mode/login_spec.rb'
diff --git a/.rubocop_todo/style/if_unless_modifier.yml b/.rubocop_todo/style/if_unless_modifier.yml
index a2e188dbc3c..ddc6a477b85 100644
--- a/.rubocop_todo/style/if_unless_modifier.yml
+++ b/.rubocop_todo/style/if_unless_modifier.yml
@@ -1176,7 +1176,6 @@ Style/IfUnlessModifier:
- 'spec/factories/projects.rb'
- 'spec/factories/protected_tags.rb'
- 'spec/factories/users.rb'
- - 'spec/factories_spec.rb'
- 'spec/features/admin/admin_users_spec.rb'
- 'spec/features/merge_request/batch_comments_spec.rb'
- 'spec/features/merge_request/user_sees_avatar_on_diff_notes_spec.rb'
diff --git a/app/assets/javascripts/groups/components/group_folder.vue b/app/assets/javascripts/groups/components/group_folder.vue
index 042d818338a..96162c32d52 100644
--- a/app/assets/javascripts/groups/components/group_folder.vue
+++ b/app/assets/javascripts/groups/components/group_folder.vue
@@ -39,7 +39,7 @@ export default {
</script>
<template>
- <ul class="groups-list group-list-tree">
+ <ul class="groups-list group-list-tree gl-display-flex gl-flex-direction-column gl-m-0">
<group-item
v-for="(group, index) in groups"
:key="index"
diff --git a/app/assets/javascripts/groups/components/group_item.vue b/app/assets/javascripts/groups/components/group_item.vue
index 4f21f68fa65..2241d57f96f 100644
--- a/app/assets/javascripts/groups/components/group_item.vue
+++ b/app/assets/javascripts/groups/components/group_item.vue
@@ -157,7 +157,9 @@ export default {
</a>
<div class="group-text-container d-flex flex-fill align-items-center">
<div class="group-text flex-grow-1 flex-shrink-1">
- <div class="d-flex align-items-center flex-wrap title namespace-title gl-mr-3">
+ <div
+ class="gl-display-flex gl-align-items-center gl-flex-wrap title namespace-title gl-font-weight-bold gl-mr-3"
+ >
<a
v-gl-tooltip.bottom
data-testid="group-name"
diff --git a/app/assets/javascripts/groups/components/groups.vue b/app/assets/javascripts/groups/components/groups.vue
index 313c8dadd1f..5706df0dd1b 100644
--- a/app/assets/javascripts/groups/components/groups.vue
+++ b/app/assets/javascripts/groups/components/groups.vue
@@ -43,7 +43,12 @@ export default {
<template>
<div class="groups-list-tree-container qa-groups-list-tree-container">
- <div v-if="searchEmpty" class="has-no-search-results">{{ searchEmptyMessage }}</div>
+ <div
+ v-if="searchEmpty"
+ class="has-no-search-results gl-font-style-italic gl-text-center gl-text-gray-600 gl-p-5"
+ >
+ {{ searchEmptyMessage }}
+ </div>
<template v-else>
<group-folder :groups="groups" :action="action" />
<pagination-links
diff --git a/app/assets/javascripts/groups/components/item_caret.vue b/app/assets/javascripts/groups/components/item_caret.vue
index 94d39a9c572..ef82e6d693a 100644
--- a/app/assets/javascripts/groups/components/item_caret.vue
+++ b/app/assets/javascripts/groups/components/item_caret.vue
@@ -21,7 +21,7 @@ export default {
</script>
<template>
- <span class="folder-caret gl-mr-2">
+ <span class="folder-caret gl-display-inline-block gl-text-secondary gl-w-5 gl-mr-2">
<gl-icon :size="12" :name="iconClass" />
</span>
</template>
diff --git a/app/assets/javascripts/groups/components/item_type_icon.vue b/app/assets/javascripts/groups/components/item_type_icon.vue
index 7821e604700..da4173993c5 100644
--- a/app/assets/javascripts/groups/components/item_type_icon.vue
+++ b/app/assets/javascripts/groups/components/item_type_icon.vue
@@ -24,5 +24,7 @@ export default {
</script>
<template>
- <span class="item-type-icon"> <gl-icon :name="iconClass" /> </span>
+ <span class="item-type-icon gl-display-inline-block gl-text-secondary">
+ <gl-icon :name="iconClass" />
+ </span>
</template>
diff --git a/app/assets/stylesheets/pages/groups.scss b/app/assets/stylesheets/pages/groups.scss
index 9106ecaa81d..96ca9fbcb43 100644
--- a/app/assets/stylesheets/pages/groups.scss
+++ b/app/assets/stylesheets/pages/groups.scss
@@ -6,15 +6,8 @@
.groups-list {
@include basic-list;
- display: flex;
- flex-direction: column;
- margin: 0;
li {
- .title {
- font-weight: 600;
- }
-
a {
text-decoration: none;
@@ -81,17 +74,13 @@ table.pipeline-project-metrics tr td {
}
.explore-groups.landing {
- .inner-content {
- padding: 0;
-
- p {
- margin: 7px 0 0;
- max-width: 480px;
- padding: 0 $gl-padding;
+ .inner-content p {
+ margin: 7px 0 0;
+ max-width: 480px;
+ padding: 0 $gl-padding;
- @include media-breakpoint-down(sm) {
- margin: 0 auto;
- }
+ @include media-breakpoint-down(sm) {
+ margin: 0 auto;
}
}
@@ -113,13 +102,6 @@ table.pipeline-project-metrics tr td {
}
.groups-list-tree-container {
- .has-no-search-results {
- text-align: center;
- padding: $gl-padding;
- font-style: italic;
- color: $well-light-text-color;
- }
-
> .group-list-tree > .group-row.has-children:first-child {
border-top: 0;
}
@@ -135,16 +117,6 @@ table.pipeline-project-metrics tr td {
}
}
- .folder-caret,
- .item-type-icon {
- display: inline-block;
- color: $gl-text-color-secondary;
- }
-
- .folder-caret {
- width: $gl-font-size-large;
- }
-
.item-type-icon {
margin-top: 2px;
width: 20px;
@@ -288,10 +260,3 @@ table.pipeline-project-metrics tr td {
}
}
}
-
-.js-groups-list-holder {
- .groups-list-loading {
- font-size: 34px;
- text-align: center;
- }
-}
diff --git a/app/models/issue.rb b/app/models/issue.rb
index 742db8dc8d6..09607ca5e9b 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -138,7 +138,8 @@ class Issue < ApplicationRecord
scope :with_api_entity_associations, -> {
preload(:timelogs, :closed_by, :assignees, :author, :labels, :issuable_severity,
milestone: { project: [:route, { namespace: :route }] },
- project: [:route, { namespace: :route }])
+ project: [:route, { namespace: :route }],
+ duplicated_to: { project: [:project_feature] })
}
scope :with_issue_type, ->(types) { where(issue_type: types) }
scope :without_issue_type, ->(types) { where.not(issue_type: types) }
diff --git a/app/services/merge_requests/build_service.rb b/app/services/merge_requests/build_service.rb
index da18fc62ddf..cc786ac02bd 100644
--- a/app/services/merge_requests/build_service.rb
+++ b/app/services/merge_requests/build_service.rb
@@ -223,7 +223,7 @@ module MergeRequests
# more than one commit in the MR
#
def assign_title_and_description
- assign_description_from_repository_template if Feature.enabled?(:mr_default_description_from_repo, target_project)
+ assign_description_from_repository_template
assign_title_and_description_from_commits
merge_request.title ||= title_from_issue if target_project.issues_enabled? || target_project.external_issue_tracker
merge_request.title ||= source_branch.titleize.humanize
diff --git a/config/feature_flags/development/mr_default_description_from_repo.yml b/config/feature_flags/development/closed_as_duplicate_of_issues_api.yml
index e15b049d0e0..6628feb3879 100644
--- a/config/feature_flags/development/mr_default_description_from_repo.yml
+++ b/config/feature_flags/development/closed_as_duplicate_of_issues_api.yml
@@ -1,8 +1,8 @@
---
-name: mr_default_description_from_repo
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/82398
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/361753
-milestone: '15.0'
+name: closed_as_duplicate_of_issues_api
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/89375
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/364749
+milestone: '15.1'
type: development
-group: group::code review
+group: group::respond
default_enabled: false
diff --git a/config/initializers/fips.rb b/config/initializers/fips.rb
new file mode 100644
index 00000000000..cf9b0ff4e4d
--- /dev/null
+++ b/config/initializers/fips.rb
@@ -0,0 +1,3 @@
+# frozen_string_literal: true
+
+Gitlab::FIPS.enable_fips_mode! if Gitlab::FIPS.enabled?
diff --git a/doc/api/issues.md b/doc/api/issues.md
index e7442b97582..1f5f4b4c8ae 100644
--- a/doc/api/issues.md
+++ b/doc/api/issues.md
@@ -170,7 +170,8 @@ Example response:
"self":"http://gitlab.example.com/api/v4/projects/1/issues/76",
"notes":"http://gitlab.example.com/api/v4/projects/1/issues/76/notes",
"award_emoji":"http://gitlab.example.com/api/v4/projects/1/issues/76/award_emoji",
- "project":"http://gitlab.example.com/api/v4/projects/1"
+ "project":"http://gitlab.example.com/api/v4/projects/1",
+ "closed_as_duplicate_of": "http://gitlab.example.com/api/v4/projects/1/issues/75"
},
"task_completion_status":{
"count":0,
@@ -396,7 +397,8 @@ Example response:
"self":"http://gitlab.example.com/api/v4/projects/4/issues/41",
"notes":"http://gitlab.example.com/api/v4/projects/4/issues/41/notes",
"award_emoji":"http://gitlab.example.com/api/v4/projects/4/issues/41/award_emoji",
- "project":"http://gitlab.example.com/api/v4/projects/4"
+ "project":"http://gitlab.example.com/api/v4/projects/4",
+ "closed_as_duplicate_of": "http://gitlab.example.com/api/v4/projects/1/issues/75"
},
"task_completion_status":{
"count":0,
@@ -605,7 +607,8 @@ Example response:
"self":"http://gitlab.example.com/api/v4/projects/4/issues/41",
"notes":"http://gitlab.example.com/api/v4/projects/4/issues/41/notes",
"award_emoji":"http://gitlab.example.com/api/v4/projects/4/issues/41/award_emoji",
- "project":"http://gitlab.example.com/api/v4/projects/4"
+ "project":"http://gitlab.example.com/api/v4/projects/4",
+ "closed_as_duplicate_of": "http://gitlab.example.com/api/v4/projects/1/issues/75"
},
"task_completion_status":{
"count":0,
@@ -769,7 +772,8 @@ Example response:
"self": "http://gitlab.example:3000/api/v4/projects/1/issues/1",
"notes": "http://gitlab.example:3000/api/v4/projects/1/issues/1/notes",
"award_emoji": "http://gitlab.example:3000/api/v4/projects/1/issues/1/award_emoji",
- "project": "http://gitlab.example:3000/api/v4/projects/1"
+ "project": "http://gitlab.example:3000/api/v4/projects/1",
+ "closed_as_duplicate_of": "http://gitlab.example.com/api/v4/projects/1/issues/75"
},
"moved_to_id": null,
"service_desk_reply_to": "service.desk@gitlab.com"
@@ -926,7 +930,8 @@ Example response:
"self": "http://gitlab.example.com/api/v4/projects/1/issues/2",
"notes": "http://gitlab.example.com/api/v4/projects/1/issues/2/notes",
"award_emoji": "http://gitlab.example.com/api/v4/projects/1/issues/2/award_emoji",
- "project": "http://gitlab.example.com/api/v4/projects/1"
+ "project": "http://gitlab.example.com/api/v4/projects/1",
+ "closed_as_duplicate_of": "http://gitlab.example.com/api/v4/projects/1/issues/75"
},
"task_completion_status":{
"count":0,
@@ -1074,7 +1079,8 @@ Example response:
"self": "http://gitlab.example.com/api/v4/projects/1/issues/2",
"notes": "http://gitlab.example.com/api/v4/projects/1/issues/2/notes",
"award_emoji": "http://gitlab.example.com/api/v4/projects/1/issues/2/award_emoji",
- "project": "http://gitlab.example.com/api/v4/projects/1"
+ "project": "http://gitlab.example.com/api/v4/projects/1",
+ "closed_as_duplicate_of": "http://gitlab.example.com/api/v4/projects/1/issues/75"
},
"task_completion_status":{
"count":0,
@@ -1249,7 +1255,9 @@ Example response:
"self": "http://gitlab.example.com/api/v4/projects/1/issues/2",
"notes": "http://gitlab.example.com/api/v4/projects/1/issues/2/notes",
"award_emoji": "http://gitlab.example.com/api/v4/projects/1/issues/2/award_emoji",
- "project": "http://gitlab.example.com/api/v4/projects/1"
+ "project": "http://gitlab.example.com/api/v4/projects/1",
+ "closed_as_duplicate_of": "http://gitlab.example.com/api/v4/projects/1/issues/75"
+
},
"task_completion_status":{
"count":0,
@@ -1433,7 +1441,8 @@ Example response:
"self": "http://gitlab.example.com/api/v4/projects/1/issues/2",
"notes": "http://gitlab.example.com/api/v4/projects/1/issues/2/notes",
"award_emoji": "http://gitlab.example.com/api/v4/projects/1/issues/2/award_emoji",
- "project": "http://gitlab.example.com/api/v4/projects/1"
+ "project": "http://gitlab.example.com/api/v4/projects/1",
+ "closed_as_duplicate_of": "http://gitlab.example.com/api/v4/projects/1/issues/75"
},
"task_completion_status":{
"count":0,
@@ -1586,7 +1595,8 @@ Example response:
"self":"https://gitlab.example.com/api/v4/projects/143/issues/1",
"notes":"https://gitlab.example.com/api/v4/projects/143/issues/1/notes",
"award_emoji":"https://gitlab.example.com/api/v4/projects/143/issues/1/award_emoji",
- "project":"https://gitlab.example.com/api/v4/projects/143"
+ "project":"https://gitlab.example.com/api/v4/projects/143",
+ "closed_as_duplicate_of": "http://gitlab.example.com/api/v4/projects/1/issues/75"
},
"references":{
"short":"#1",
@@ -1683,7 +1693,8 @@ Example response:
"self": "http://gitlab.example.com/api/v4/projects/1/issues/2",
"notes": "http://gitlab.example.com/api/v4/projects/1/issues/2/notes",
"award_emoji": "http://gitlab.example.com/api/v4/projects/1/issues/2/award_emoji",
- "project": "http://gitlab.example.com/api/v4/projects/1"
+ "project": "http://gitlab.example.com/api/v4/projects/1",
+ "closed_as_duplicate_of": "http://gitlab.example.com/api/v4/projects/1/issues/75"
},
"task_completion_status":{
"count":0,
diff --git a/doc/development/testing_guide/best_practices.md b/doc/development/testing_guide/best_practices.md
index 3b2eb5a2cfa..eda1c8c3d10 100644
--- a/doc/development/testing_guide/best_practices.md
+++ b/doc/development/testing_guide/best_practices.md
@@ -1338,7 +1338,7 @@ GitLab uses [factory_bot](https://github.com/thoughtbot/factory_bot) as a test f
See [issue #262624](https://gitlab.com/gitlab-org/gitlab/-/issues/262624) for further context.
- Factories don't have to be limited to `ActiveRecord` objects.
[See example](https://gitlab.com/gitlab-org/gitlab-foss/commit/0b8cefd3b2385a21cfed779bd659978c0402766d).
-- Factories and their traits should produce valid objects that are [verified by specs](https://gitlab.com/gitlab-org/gitlab/-/blob/master/spec/factories_spec.rb).
+- Factories and their traits should produce valid objects that are [verified by specs](https://gitlab.com/gitlab-org/gitlab/-/blob/master/spec/models/factories_spec.rb).
- Avoid the use of [`skip_callback`](https://api.rubyonrails.org/classes/ActiveSupport/Callbacks/ClassMethods.html#method-i-skip_callback) in factories.
See [issue #247865](https://gitlab.com/gitlab-org/gitlab/-/issues/247865) for details.
diff --git a/doc/development/testing_guide/testing_levels.md b/doc/development/testing_guide/testing_levels.md
index 9ca2d0db93c..02f32a031dc 100644
--- a/doc/development/testing_guide/testing_levels.md
+++ b/doc/development/testing_guide/testing_levels.md
@@ -55,7 +55,6 @@ records should use stubs/doubles as much as possible.
| `lib/` | `spec/lib/` | RSpec | |
| `lib/tasks/` | `spec/tasks/` | RSpec | |
| `rubocop/` | `spec/rubocop/` | RSpec | |
-| `spec/factories` | `spec/factories_spec.rb` | RSpec | |
### Frontend unit tests
diff --git a/doc/user/application_security/index.md b/doc/user/application_security/index.md
index df24a0dcc3c..d449fbb9a6c 100644
--- a/doc/user/application_security/index.md
+++ b/doc/user/application_security/index.md
@@ -139,9 +139,14 @@ variables:
### Override the default registry base address
By default, GitLab security scanners use `registry.gitlab.com/security-products` as the
-base address for Docker images. You can override this globally by setting the CI/CD variable
+base address for Docker images. You can override this for most scanners by setting the CI/CD variable
`SECURE_ANALYZERS_PREFIX` to another location. Note that this affects all scanners at once.
+The [Container Scanning](container_scanning/index.md) analyzer is an exception, and it
+does not use the `SECURE_ANALYZERS_PREFIX` variable. To override its Docker image, see
+the instructions for [Running container scanning in an offline
+environment](container_scanning/index.md#running-container-scanning-in-an-offline-environment).
+
### Use security scanning tools with merge request pipelines
By default, the application security jobs are configured to run for branch pipelines only.
diff --git a/lib/api/entities/issue.rb b/lib/api/entities/issue.rb
index f87ef093cd8..1060b2c517a 100644
--- a/lib/api/entities/issue.rb
+++ b/lib/api/entities/issue.rb
@@ -29,6 +29,16 @@ module API
expose :project do |issue|
expose_url(api_v4_projects_path(id: issue.project_id))
end
+
+ expose :closed_as_duplicate_of do |issue|
+ if ::Feature.enabled?(:closed_as_duplicate_of_issues_api, issue.project) &&
+ issue.duplicated? &&
+ options[:current_user]&.can?(:read_issue, issue.duplicated_to)
+ expose_url(
+ api_v4_project_issue_path(id: issue.duplicated_to.project_id, issue_iid: issue.duplicated_to.iid)
+ )
+ end
+ end
end
expose :references, with: IssuableReferences do |issue|
diff --git a/lib/gitlab/fips.rb b/lib/gitlab/fips.rb
index 97813f13a91..a7106dd70e9 100644
--- a/lib/gitlab/fips.rb
+++ b/lib/gitlab/fips.rb
@@ -16,6 +16,8 @@ module Gitlab
Technology.new(:ed25519_sk, SSHData::PublicKey::SKED25519, [256], %w(sk-ssh-ed25519@openssh.com))
].freeze
+ OPENSSL_DIGESTS = %i(SHA1 SHA256 SHA384 SHA512).freeze
+
class << self
# Returns whether we should be running in FIPS mode or not
#
@@ -29,6 +31,21 @@ module Gitlab
false
end
+
+ # Swap Ruby's Digest::SHAx implementations for OpenSSL::Digest::SHAx.
+ def enable_fips_mode!
+ require 'digest'
+
+ use_openssl_digest(:SHA2, :SHA256)
+ OPENSSL_DIGESTS.each { |alg| use_openssl_digest(alg, alg) }
+ end
+
+ private
+
+ def use_openssl_digest(ruby_algorithm, openssl_algorithm)
+ Digest.send(:remove_const, ruby_algorithm) # rubocop:disable GitlabSecurity/PublicSend
+ Digest.const_set(ruby_algorithm, OpenSSL::Digest.const_get(openssl_algorithm, false))
+ end
end
end
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 6104f371c22..3c327c71a9e 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -34107,9 +34107,6 @@ msgstr ""
msgid "SecurityOrchestration|Scan execution policy"
msgstr ""
-msgid "SecurityOrchestration|Scan execution policy allow to create rules which forces security scans for particular branches at certain time. Supported types are SAST, DAST, Secret detection, Container scan, License scan, API fuzzing, coverage-guided fuzzing."
-msgstr ""
-
msgid "SecurityOrchestration|Scan result"
msgstr ""
@@ -34209,6 +34206,9 @@ msgstr ""
msgid "SecurityOrchestration|Update scan policies"
msgstr ""
+msgid "SecurityOrchestration|Use a scan execution policy to create rules which enforce security scans for particular branches at a certain time. Supported types are SAST, DAST, Secret detection, and Container scanning."
+msgstr ""
+
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
msgstr ""
@@ -40192,9 +40192,6 @@ msgstr ""
msgid "Trial|Please select a country"
msgstr ""
-msgid "Trial|Successful trial activation image"
-msgstr ""
-
msgid "Trial|Telephone number"
msgstr ""
diff --git a/qa/qa/resource/api_fabricator.rb b/qa/qa/resource/api_fabricator.rb
index 79cb1ebebc9..667dbc03fc3 100644
--- a/qa/qa/resource/api_fabricator.rb
+++ b/qa/qa/resource/api_fabricator.rb
@@ -118,7 +118,7 @@ module QA
MSG
end
- body[:id] = body.fetch(:id).split('/').last
+ body[:id] = body.fetch(:id).split('/').last if body.key?(:id)
body.transform_keys { |key| key.to_s.underscore.to_sym }
else
diff --git a/scripts/verify-tff-mapping b/scripts/verify-tff-mapping
index b3462f74faa..9eb1d43c65b 100755
--- a/scripts/verify-tff-mapping
+++ b/scripts/verify-tff-mapping
@@ -67,13 +67,13 @@ tests = [
{
explanation: 'FOSS factory should map to factories spec',
source: 'spec/factories/users.rb',
- expected: ['spec/factories_spec.rb']
+ expected: ['spec/models/factories_spec.rb']
},
{
explanation: 'EE factory should map to factories spec',
source: 'ee/spec/factories/users.rb',
- expected: ['spec/factories_spec.rb']
+ expected: ['spec/models/factories_spec.rb']
},
{
diff --git a/spec/factories/issues.rb b/spec/factories/issues.rb
index 8c714f7736f..88522737e06 100644
--- a/spec/factories/issues.rb
+++ b/spec/factories/issues.rb
@@ -41,6 +41,13 @@ FactoryBot.define do
end
end
+ trait :closed_as_duplicate do
+ closed
+ after(:create) do |issue|
+ issue.update!(duplicated_to: create(:issue, project: issue.project))
+ end
+ end
+
after(:build) do |issue, evaluator|
issue.state_id = Issue.available_states[evaluator.state]
end
diff --git a/spec/lib/gitlab/fips_spec.rb b/spec/lib/gitlab/fips_spec.rb
index 4d19a44f617..a6c9d54c0fb 100644
--- a/spec/lib/gitlab/fips_spec.rb
+++ b/spec/lib/gitlab/fips_spec.rb
@@ -48,4 +48,51 @@ RSpec.describe Gitlab::FIPS do
end
end
end
+
+ describe '.enable_fips_mode!' do
+ let(:digests) { {} }
+ let(:test_string) { 'abc' }
+
+ before do
+ described_class::OPENSSL_DIGESTS.each do |digest|
+ digests[digest] = Digest.const_get(digest, false)
+ end
+ end
+
+ after do
+ digests.each do |name, value|
+ Digest.send(:remove_const, name)
+ Digest.const_set(name, value)
+ end
+ end
+
+ it 'assigns OpenSSL digests' do
+ described_class.enable_fips_mode!
+
+ # rubocop:disable Fips/OpenSSL
+ # rubocop:disable Fips/SHA1
+ # rubocop:disable Layout/LineLength
+ expect(Digest::SHA1).to be(OpenSSL::Digest::SHA1)
+ expect(Digest::SHA2).to be(OpenSSL::Digest::SHA256)
+ expect(Digest::SHA256).to be(OpenSSL::Digest::SHA256)
+ expect(Digest::SHA384).to be(OpenSSL::Digest::SHA384)
+ expect(Digest::SHA512).to be(OpenSSL::Digest::SHA512)
+
+ # From https://www.nist.gov/itl/ssd/software-quality-group/nsrl-test-data
+ expect(Digest::SHA1.hexdigest(test_string)).to eq('a9993e364706816aba3e25717850c26c9cd0d89d')
+ expect(Digest::SHA2.hexdigest(test_string)).to eq('ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad')
+ expect(Digest::SHA256.hexdigest(test_string)).to eq('ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad')
+ expect(Digest::SHA384.hexdigest(test_string)).to eq('cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7')
+ expect(Digest::SHA512.hexdigest(test_string)).to eq('ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f')
+
+ expect(Digest::SHA1.base64digest(test_string)).to eq('qZk+NkcGgWq6PiVxeFDCbJzQ2J0=')
+ expect(Digest::SHA2.base64digest(test_string)).to eq('ungWv48Bz+pBQUDeXa4iI7ADYaOWF3qctBD/YfIAFa0=')
+ expect(Digest::SHA256.base64digest(test_string)).to eq('ungWv48Bz+pBQUDeXa4iI7ADYaOWF3qctBD/YfIAFa0=')
+ expect(Digest::SHA384.base64digest(test_string)).to eq('ywB1P0WjXou1oD1pmsZQBycsMqsO3tFjGotgWkP/W+2AhgcroefMI1i67KE0yCWn')
+ expect(Digest::SHA512.base64digest(test_string)).to eq('3a81oZNherrMQXNJriBBMRLm+k6JqX6iCp7u5ktV05ohkpkqJ0/BqDa6PCOj/uu9RU1EI2Q86A4qmslPpUyknw==')
+ # rubocop:enable Fips/OpenSSL
+ # rubocop:enable Fips/SHA1
+ # rubocop:enable Layout/LineLength
+ end
+ end
end
diff --git a/spec/factories_spec.rb b/spec/models/factories_spec.rb
index 08286f57b3b..45c3f93e6cf 100644
--- a/spec/factories_spec.rb
+++ b/spec/models/factories_spec.rb
@@ -51,7 +51,9 @@ RSpec.describe 'factories' do
factory.definition.defined_traits.map(&:name).each do |trait_name|
describe "linting :#{trait_name} trait" do
it 'does not raise error when created' do
- pending("Trait skipped linting due to legacy error") if skipped_traits.include?([factory.name, trait_name.to_sym])
+ if skipped_traits.include?([factory.name, trait_name.to_sym])
+ pending("Trait skipped linting due to legacy error")
+ end
expect { create(factory.name, trait_name) }.not_to raise_error
end
diff --git a/spec/requests/api/issues/issues_spec.rb b/spec/requests/api/issues/issues_spec.rb
index 1419d39981a..480baff6eed 100644
--- a/spec/requests/api/issues/issues_spec.rb
+++ b/spec/requests/api/issues/issues_spec.rb
@@ -575,6 +575,26 @@ RSpec.describe API::Issues do
end
end
+ context 'with issues closed as duplicates' do
+ let_it_be(:dup_issue_1) { create(:issue, :closed_as_duplicate, project: project) }
+
+ it 'avoids N+1 queries' do
+ get api('/issues', user) # warm up
+
+ control = ActiveRecord::QueryRecorder.new do
+ get api('/issues', user)
+ end
+
+ create(:issue, :closed_as_duplicate, project: project)
+
+ expect do
+ get api('/issues', user)
+ end.not_to exceed_query_limit(control)
+ # 2 pre-existed issues + 2 duplicated incidents (2 closed, 2 new)
+ expect(json_response.count).to eq(6)
+ end
+ end
+
context 'filter by labels or label_name param' do
context 'N+1' do
let(:label_b) { create(:label, title: 'foo', project: project) }
@@ -1101,6 +1121,51 @@ RSpec.describe API::Issues do
expect(json_response['references']['relative']).to eq("##{issue.iid}")
expect(json_response['references']['full']).to eq("#{project.parent.path}/#{project.path}##{issue.iid}")
end
+
+ context 'when issue is closed as duplicate' do
+ let(:new_issue) { create(:issue) }
+ let!(:issue_closed_as_dup) { create(:issue, project: project, duplicated_to: new_issue) }
+
+ before do
+ project.add_developer(user)
+ end
+
+ context 'user does not have permission to view new issue' do
+ it 'does not return the issue as closed_as_duplicate_of' do
+ get api("/projects/#{project.id}/issues/#{issue_closed_as_dup.iid}", user)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response.dig('_links', 'closed_as_duplicate_of')).to eq(nil)
+ end
+ end
+
+ context 'when user has access to new issue' do
+ before do
+ new_issue.project.add_guest(user)
+ end
+
+ it 'returns the issue as closed_as_duplicate_of' do
+ get api("/projects/#{project.id}/issues/#{issue_closed_as_dup.iid}", user)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expected_url = expose_url(api_v4_project_issue_path(id: new_issue.project_id, issue_iid: new_issue.iid))
+ expect(json_response.dig('_links', 'closed_as_duplicate_of')).to eq(expected_url)
+ end
+
+ context 'feature flag is disabled' do
+ before do
+ stub_feature_flags(closed_as_duplicate_of_issues_api: false)
+ end
+
+ it 'does not return the issue as closed_as_duplicate_of' do
+ get api("/projects/#{project.id}/issues/#{issue_closed_as_dup.iid}", user)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response.dig('_links', 'closed_as_duplicate_of')).to eq(nil)
+ end
+ end
+ end
+ end
end
describe "POST /projects/:id/issues" do
diff --git a/spec/services/merge_requests/build_service_spec.rb b/spec/services/merge_requests/build_service_spec.rb
index b273f54360d..3c9d2271ddc 100644
--- a/spec/services/merge_requests/build_service_spec.rb
+++ b/spec/services/merge_requests/build_service_spec.rb
@@ -83,24 +83,8 @@ RSpec.describe MergeRequests::BuildService do
let(:files) { { '.gitlab/merge_request_templates/Default.md' => 'Default template contents' } }
let(:project) { create(:project, :custom_repo, files: files ) }
- context 'when mr_default_description_from_repo feature flag is enabled' do
- before do
- stub_feature_flags(mr_default_description_from_repo: project)
- end
-
- it 'the template description is preferred' do
- expect(merge_request.description).to eq('Default template contents')
- end
- end
-
- context 'when mr_default_description_from_repo feature flag is disabled' do
- before do
- stub_feature_flags(mr_default_description_from_repo: false)
- end
-
- it 'the template description is not preferred' do
- expect(merge_request.description).not_to eq('Default template contents')
- end
+ it 'the template description is preferred' do
+ expect(merge_request.description).to eq('Default template contents')
end
end
@@ -312,28 +296,10 @@ RSpec.describe MergeRequests::BuildService do
let(:files) { { '.gitlab/merge_request_templates/Default.md' => 'Default template contents' } }
let(:project) { create(:project, :custom_repo, files: files ) }
- context 'when mr_default_description_from_repo feature flag is enabled' do
- before do
- stub_feature_flags(mr_default_description_from_repo: project)
- end
-
- it 'appends the closing description to a Default.md template' do
- expected_description = ['Default template contents', closing_message].compact.join("\n\n")
-
- expect(merge_request.description).to eq(expected_description)
- end
- end
-
- context 'when mr_default_description_from_repo feature flag is disabled' do
- before do
- stub_feature_flags(mr_default_description_from_repo: false)
- end
-
- it 'appends the closing description to the commit description' do
- expected_description = ['Create the app', closing_message].compact.join("\n\n")
+ it 'appends the closing description to a Default.md template' do
+ expected_description = ['Default template contents', closing_message].compact.join("\n\n")
- expect(merge_request.description).to eq(expected_description)
- end
+ expect(merge_request.description).to eq(expected_description)
end
end
end
@@ -410,24 +376,8 @@ RSpec.describe MergeRequests::BuildService do
let(:files) { { '.gitlab/merge_request_templates/Default.md' => 'Default template contents' } }
let(:project) { create(:project, :custom_repo, files: files ) }
- context 'when mr_default_description_from_repo feature flag is enabled' do
- before do
- stub_feature_flags(mr_default_description_from_repo: project)
- end
-
- it 'keeps the description from the initial params' do
- expect(merge_request.description).to eq(description)
- end
- end
-
- context 'when mr_default_description_from_repo feature flag is disabled' do
- before do
- stub_feature_flags(mr_default_description_from_repo: false)
- end
-
- it 'keeps the description from the initial params' do
- expect(merge_request.description).to eq(description)
- end
+ it 'keeps the description from the initial params' do
+ expect(merge_request.description).to eq(description)
end
end
end
@@ -465,26 +415,10 @@ RSpec.describe MergeRequests::BuildService do
let(:files) { { '.gitlab/merge_request_templates/Default.md' => 'Default template contents' } }
let(:project) { create(:project, :custom_repo, files: files ) }
- context 'when mr_default_description_from_repo feature flag is enabled' do
- before do
- stub_feature_flags(mr_default_description_from_repo: project)
- end
-
- it 'appends the closing description to a Default.md template' do
- expected_description = ['Default template contents', closing_message].compact.join("\n\n")
+ it 'appends the closing description to a Default.md template' do
+ expected_description = ['Default template contents', closing_message].compact.join("\n\n")
- expect(merge_request.description).to eq(expected_description)
- end
- end
-
- context 'when mr_default_description_from_repo feature flag is disabled' do
- before do
- stub_feature_flags(mr_default_description_from_repo: false)
- end
-
- it 'sets the closing description' do
- expect(merge_request.description).to eq(closing_message)
- end
+ expect(merge_request.description).to eq(expected_description)
end
end
end
@@ -542,28 +476,10 @@ RSpec.describe MergeRequests::BuildService do
let(:files) { { '.gitlab/merge_request_templates/Default.md' => 'Default template contents' } }
let(:project) { create(:project, :custom_repo, files: files ) }
- context 'when mr_default_description_from_repo feature flag is enabled' do
- before do
- stub_feature_flags(mr_default_description_from_repo: project)
- end
-
- it 'appends the closing description to a Default.md template' do
- expected_description = ['Default template contents', closing_message].compact.join("\n\n")
-
- expect(merge_request.description).to eq(expected_description)
- end
- end
-
- context 'when mr_default_description_from_repo feature flag is disabled' do
- before do
- stub_feature_flags(mr_default_description_from_repo: false)
- end
-
- it 'appends the closing description to the commit description' do
- expected_description = ['Create the app', closing_message].compact.join("\n\n")
+ it 'appends the closing description to a Default.md template' do
+ expected_description = ['Default template contents', closing_message].compact.join("\n\n")
- expect(merge_request.description).to eq(expected_description)
- end
+ expect(merge_request.description).to eq(expected_description)
end
end
end
diff --git a/spec/tooling/lib/tooling/test_map_generator_spec.rb b/spec/tooling/lib/tooling/test_map_generator_spec.rb
index b52d78b01a3..1b369923d8d 100644
--- a/spec/tooling/lib/tooling/test_map_generator_spec.rb
+++ b/spec/tooling/lib/tooling/test_map_generator_spec.rb
@@ -17,7 +17,7 @@ RSpec.describe Tooling::TestMapGenerator do
:timestamp: 1602668405
:version:
---
- "./spec/factories_spec.rb[1]":
+ "./spec/models/factories_spec.rb[1]":
- lib/gitlab/current_settings.rb
- lib/feature.rb
- lib/gitlab/marginalia.rb
@@ -62,13 +62,13 @@ RSpec.describe Tooling::TestMapGenerator do
let(:expected_mapping) do
{
'lib/gitlab/current_settings.rb' => [
- 'spec/factories_spec.rb'
+ 'spec/models/factories_spec.rb'
],
'lib/feature.rb' => [
- 'spec/factories_spec.rb'
+ 'spec/models/factories_spec.rb'
],
'lib/gitlab/marginalia.rb' => [
- 'spec/factories_spec.rb'
+ 'spec/models/factories_spec.rb'
]
}
end
@@ -96,15 +96,15 @@ RSpec.describe Tooling::TestMapGenerator do
let(:expected_mapping) do
{
'lib/gitlab/current_settings.rb' => [
- 'spec/factories_spec.rb',
+ 'spec/models/factories_spec.rb',
'spec/models/project_spec.rb'
],
'lib/feature.rb' => [
- 'spec/factories_spec.rb',
+ 'spec/models/factories_spec.rb',
'spec/models/project_spec.rb'
],
'lib/gitlab/marginalia.rb' => [
- 'spec/factories_spec.rb',
+ 'spec/models/factories_spec.rb',
'spec/models/project_spec.rb'
]
}
diff --git a/tests.yml b/tests.yml
index 15b1814df3a..5fb0abe20b0 100644
--- a/tests.yml
+++ b/tests.yml
@@ -51,7 +51,7 @@ mapping:
# EE/FOSS factory should map to factories spec
- source: (ee/)?spec/factories/.+\.rb
- test: spec/factories_spec.rb
+ test: spec/models/factories_spec.rb
# Whats New should map to its respective spec
- source: data/whats_new/\w*.yml
diff --git a/tooling/quality/test_level.rb b/tooling/quality/test_level.rb
index e6945ddb526..d0f2bd0107b 100644
--- a/tooling/quality/test_level.rb
+++ b/tooling/quality/test_level.rb
@@ -81,10 +81,6 @@ module Quality
@regexps[level] ||= Regexp.new("#{prefixes_for_regex}spec/#{folders_regex(level)}").freeze
end
- def legacy_factories_regexp
- @legacy_factories_regexp ||= %r{spec/factories_spec.rb}.freeze
- end
-
def level_for(file_path)
case file_path
# Detect migration first since some background migration tests are under
@@ -100,8 +96,6 @@ module Quality
:integration
when regexp(:system)
:system
- when legacy_factories_regexp
- :unit
else
raise UnknownTestLevelError, "Test level for #{file_path} couldn't be set. Please rename the file properly or change the test level detection regexes in #{__FILE__}."
end