diff --git a/.rubocop_todo/database/multiple_databases.yml b/.rubocop_todo/database/multiple_databases.yml
index 7cc54a5b373..08ce72f7f51 100644
--- a/.rubocop_todo/database/multiple_databases.yml
+++ b/.rubocop_todo/database/multiple_databases.yml
@@ -2,7 +2,6 @@
Database/MultipleDatabases:
Exclude:
- 'config/initializers/active_record_data_types.rb'
- - 'config/initializers/active_record_lifecycle.rb'
- 'config/initializers/sidekiq.rb'
- 'db/post_migrate/20210317104032_set_iteration_cadence_automatic_to_false.rb'
- 'db/post_migrate/20210811122206_update_external_project_bots.rb'
diff --git a/app/assets/javascripts/projects/settings_service_desk/components/service_desk_setting.vue b/app/assets/javascripts/projects/settings_service_desk/components/service_desk_setting.vue
index 05c1f2d4a1e..8a9a0b541f3 100644
--- a/app/assets/javascripts/projects/settings_service_desk/components/service_desk_setting.vue
+++ b/app/assets/javascripts/projects/settings_service_desk/components/service_desk_setting.vue
@@ -270,18 +270,16 @@ export default {
-
-
- {{ __('Save changes') }}
-
-
+
+ {{ __('Save changes') }}
+
diff --git a/app/graphql/types/ci/runner_status_enum.rb b/app/graphql/types/ci/runner_status_enum.rb
index 9ba680975f4..e8bd3d15a54 100644
--- a/app/graphql/types/ci/runner_status_enum.rb
+++ b/app/graphql/types/ci/runner_status_enum.rb
@@ -28,12 +28,13 @@ module Types
value: :online
value 'OFFLINE',
- description: "Runner that has not contacted this instance within the last #{::Ci::Runner::ONLINE_CONTACT_TIMEOUT.inspect}.",
- deprecated: { reason: 'This field will have a slightly different scope starting in 15.0, with STALE being returned after a certain period offline', milestone: '14.6' },
+ description: "Runner that has not contacted this instance within the " \
+ "last #{::Ci::Runner::ONLINE_CONTACT_TIMEOUT.inspect}. Will be considered `STALE` if offline for " \
+ "more than #{::Ci::Runner::STALE_TIMEOUT.inspect}.",
value: :offline
value 'STALE',
- description: "Runner that has not contacted this instance within the last #{::Ci::Runner::STALE_TIMEOUT.inspect}. Only available if legacyMode is null. Will be a possible return value starting in 15.0.",
+ description: "Runner that has not contacted this instance within the last #{::Ci::Runner::STALE_TIMEOUT.inspect}.",
value: :stale
value 'NEVER_CONTACTED',
diff --git a/app/models/ci/runner.rb b/app/models/ci/runner.rb
index 53cf7c080ad..7a1d52f5aea 100644
--- a/app/models/ci/runner.rb
+++ b/app/models/ci/runner.rb
@@ -60,7 +60,7 @@ module Ci
AVAILABLE_TYPES_LEGACY = %w[specific shared].freeze
AVAILABLE_TYPES = runner_types.keys.freeze
- AVAILABLE_STATUSES = %w[active paused online offline never_contacted stale].freeze # TODO: Remove in %16.0: active, paused. Relevant issues: https://gitlab.com/gitlab-org/gitlab/-/issues/347303, https://gitlab.com/gitlab-org/gitlab/-/issues/344648
+ AVAILABLE_STATUSES = %w[active paused online offline never_contacted stale].freeze # TODO: Remove in %16.0: active, paused. Relevant issue: https://gitlab.com/gitlab-org/gitlab/-/issues/344648
AVAILABLE_SCOPES = (AVAILABLE_TYPES_LEGACY + AVAILABLE_TYPES + AVAILABLE_STATUSES).freeze
FORM_EDITABLE = %i[description tag_list active run_untagged locked access_level maximum_timeout_human_readable].freeze
@@ -336,6 +336,8 @@ module Ci
# DEPRECATED
# TODO Remove in %16.0 in favor of `status` for REST calls, see https://gitlab.com/gitlab-org/gitlab/-/issues/344648
def deprecated_rest_status
+ return :stale if stale?
+
if contacted_at.nil?
:never_contacted
elsif active?
diff --git a/app/models/concerns/bulk_member_access_load.rb b/app/models/concerns/bulk_member_access_load.rb
index efc65e55e40..c3aa3019abb 100644
--- a/app/models/concerns/bulk_member_access_load.rb
+++ b/app/models/concerns/bulk_member_access_load.rb
@@ -12,6 +12,11 @@ module BulkMemberAccessLoad
end
end
+ def purge_resource_id_from_request_store(resource_klass, resource_id)
+ Gitlab::SafeRequestPurger.execute(resource_key: max_member_access_for_resource_key(resource_klass),
+ resource_ids: [resource_id])
+ end
+
def max_member_access_for_resource_key(klass)
"max_member_access_for_#{klass.name.underscore.pluralize}:#{self.class}:#{self.id}"
end
diff --git a/app/models/project_team.rb b/app/models/project_team.rb
index 4b89d95c1a3..bb5363598df 100644
--- a/app/models/project_team.rb
+++ b/app/models/project_team.rb
@@ -193,6 +193,10 @@ class ProjectTeam
project.merge_value_to_request_store(User, user_id, project_access_level)
end
+ def purge_member_access_cache_for_user_id(user_id)
+ project.purge_resource_id_from_request_store(User, user_id)
+ end
+
def max_member_access(user_id)
max_member_access_for_user_ids([user_id])[user_id]
end
diff --git a/app/services/members/projects/creator_service.rb b/app/services/members/projects/creator_service.rb
index d92fe60c54a..9e9389d3c18 100644
--- a/app/services/members/projects/creator_service.rb
+++ b/app/services/members/projects/creator_service.rb
@@ -6,16 +6,11 @@ module Members
private
def can_create_new_member?
- # order is important here!
- # The `admin_project_member` check has side-effects that causes projects not be created if this area is hit
- # during project creation.
- # Call that triggers is current_user.can?(:admin_project_member, member.project)
- # I tracked back to base_policy.rb admin check and specifically in
- # Gitlab::Auth::CurrentUserMode.new(@user).admin_mode? call.
- # This calls user.admin? and that specific call causes issues with project creation in
- # spec/requests/api/projects_spec.rb specs and others, mostly around project creation.
- # https://gitlab.com/gitlab-org/gitlab/-/issues/358931 for investigation
- adding_the_creator_as_owner_in_a_personal_project? || current_user.can?(:admin_project_member, member.project)
+ # This access check(`admin_project_member`) will write to safe request store cache for the user being added.
+ # This means any operations inside the same request will need to purge that safe request
+ # store cache if operations are needed to be done inside the same request that checks max member access again on
+ # that user.
+ current_user.can?(:admin_project_member, member.project) || adding_the_creator_as_owner_in_a_personal_project?
end
def can_update_existing_member?
diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb
index b051efcde94..c7f284bec9b 100644
--- a/app/services/projects/create_service.rb
+++ b/app/services/projects/create_service.rb
@@ -161,6 +161,13 @@ module Projects
)
else
@project.add_owner(@project.namespace.owner, current_user: current_user)
+ # During the process of adding a project owner, a check on permissions is made on the user which caches
+ # the max member access for that user on this project.
+ # Since that is `0` before the member is created - and we are still inside the request
+ # cycle when we need to do other operations that might check those permissions (e.g. write a commit)
+ # we need to purge that cache so that the updated permissions is fetched instead of using the outdated cached value of 0
+ # from before member creation
+ @project.team.purge_member_access_cache_for_user_id(@project.namespace.owner.id)
end
end
diff --git a/config/initializers/active_record_lifecycle.rb b/config/initializers/active_record_lifecycle.rb
index 92cc1d81617..73df2b41a04 100644
--- a/config/initializers/active_record_lifecycle.rb
+++ b/config/initializers/active_record_lifecycle.rb
@@ -5,7 +5,9 @@
if defined?(ActiveRecord::Base) && !Gitlab::Runtime.sidekiq?
Gitlab::Cluster::LifecycleEvents.on_worker_start do
ActiveSupport.on_load(:active_record) do
- ActiveRecord::Base.establish_connection # rubocop: disable Database/EstablishConnection
+ # rubocop:disable Database/MultipleDatabases
+ ActiveRecord::Base.establish_connection # rubocop:disable Database/EstablishConnection
+ # rubocop:enable Database/MultipleDatabases
Gitlab::AppLogger.debug("ActiveRecord connection established")
end
@@ -18,8 +20,8 @@ if defined?(ActiveRecord::Base)
# the following is highly recommended for Rails + "preload_app true"
# as there's no need for the master process to hold a connection
- ActiveRecord::Base.connection.disconnect!
+ ActiveRecord::Base.clear_all_connections! # rubocop:disable Database/MultipleDatabases
- Gitlab::AppLogger.debug("ActiveRecord connection disconnected")
+ Gitlab::AppLogger.debug("ActiveRecord connections disconnected")
end
end
diff --git a/data/deprecations/14-6-runner_api_new_stale_status_breaking_change.yml b/data/removals/15_0/15-0-runner_api_new_stale_status_breaking_change.yml
similarity index 68%
rename from data/deprecations/14-6-runner_api_new_stale_status_breaking_change.yml
rename to data/removals/15_0/15-0-runner_api_new_stale_status_breaking_change.yml
index 0f21318d329..905bc3befce 100644
--- a/data/deprecations/14-6-runner_api_new_stale_status_breaking_change.yml
+++ b/data/removals/15_0/15-0-runner_api_new_stale_status_breaking_change.yml
@@ -5,9 +5,12 @@
removal_date: "2022-05-22"
breaking_change: true
body: | # Do not modify this line, instead modify the lines below.
- A breaking change will occur for the Runner [API](https://docs.gitlab.com/ee/api/runners.html#runners-api) endpoints in 15.0.
+ A breaking change was made to the Runner [API](https://docs.gitlab.com/ee/api/runners.html#runners-api) endpoints
+ in 15.0.
- Instead of the GitLab Runner API endpoints returning `offline` and `not_connected` for runners that have not contacted the GitLab instance in the past three months, the API endpoints will return the `stale` value, which was introduced in 14.6.
+ Instead of the GitLab Runner API endpoints returning `offline` and `not_connected` for runners that have not
+ contacted the GitLab instance in the past three months, the API endpoints now return the `stale` value,
+ which was introduced in 14.6.
stage: Verify
tiers: [Core, Premium, Ultimate]
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/347303
diff --git a/doc/administration/gitaly/praefect.md b/doc/administration/gitaly/praefect.md
index 6083b9e1dd8..bd986b75142 100644
--- a/doc/administration/gitaly/praefect.md
+++ b/doc/administration/gitaly/praefect.md
@@ -1245,12 +1245,14 @@ workers from verifying the same replica concurrently. The worker releases the le
Praefect contains a background goroutine that releases stale leases every 10 seconds when workers are terminated for
some reason without releasing the lease.
-The worker logs each of the metadata removals prior to executing them. For example:
+The worker logs each of the metadata removals prior to executing them. The `perform_deletions` key
+indicates whether the invalid metadata records are actually deleted or not. For example:
```json
{
"level": "info",
"msg": "removing metadata records of non-existent replicas",
+ "perform_deletions": false,
"replicas": {
"default": {
"@hashed/6b/86/6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b.git": [
@@ -1261,15 +1263,15 @@ The worker logs each of the metadata removals prior to executing them. For examp
}
```
-### Enable verification worker
+### Configure the verification worker
-The worker is disabled by default. It can be enabled by configuring the verification interval. The interval
-accepts any valid [Go duration string](https://pkg.go.dev/time#ParseDuration).
+The worker is enabled by default and verifies the metadata records every seven days. The verification
+interval is configurable with any valid [Go duration string](https://pkg.go.dev/time#ParseDuration).
-To enable the worker and verify replicas every 7 days:
+To verify the metadata every three days:
```ruby
-praefect['background_verification_verification_interval'] = '168h'
+praefect['background_verification_verification_interval'] = '72h'
```
Values of 0 and below disable the background verifier.
@@ -1278,6 +1280,23 @@ Values of 0 and below disable the background verifier.
praefect['background_verification_verification_interval'] = '0'
```
+#### Enable deletions
+
+WARNING:
+Deletions are disabled by default due to a race condition with repository renames that can cause incorrect
+deletions. This is especially prominent in Geo instances as Geo performs more renames than instances without Geo.
+See [Handle repository creations, deletions and renames atomically](https://gitlab.com/gitlab-org/gitaly/-/merge_requests/4101)
+for progress on a fix. We do not recommend enabling the deletions until this is fixed.
+
+By default, the worker does not delete invalid metadata records but simply logs them and outputs Prometheus
+metrics for them.
+
+You can enable deleting invalid metadata records with:
+
+```ruby
+praefect['background_verification_delete_invalid_records'] = true
+```
+
### Prioritize verification manually
You can prioritize verification of some replicas ahead of their next scheduled verification time.
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 477936d8ed0..2c12f99ad06 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -17994,10 +17994,10 @@ Values for sorting runners.
| ----- | ----------- |
| `ACTIVE` **{warning-solid}** | **Deprecated** in 14.6. This was renamed. Use: [`CiRunner.paused`](#cirunnerpaused). |
| `NEVER_CONTACTED` | Runner that has never contacted this instance. |
-| `OFFLINE` **{warning-solid}** | **Deprecated** in 14.6. This field will have a slightly different scope starting in 15.0, with STALE being returned after a certain period offline. |
+| `OFFLINE` | Runner that has not contacted this instance within the last 2 hours. Will be considered `STALE` if offline for more than 3 months. |
| `ONLINE` | Runner that contacted this instance within the last 2 hours. |
| `PAUSED` **{warning-solid}** | **Deprecated** in 14.6. This was renamed. Use: [`CiRunner.paused`](#cirunnerpaused). |
-| `STALE` | Runner that has not contacted this instance within the last 3 months. Only available if legacyMode is null. Will be a possible return value starting in 15.0. |
+| `STALE` | Runner that has not contacted this instance within the last 3 months. |
### `CiRunnerType`
diff --git a/doc/update/deprecations.md b/doc/update/deprecations.md
index 2e104ea79d9..c626ca094fb 100644
--- a/doc/update/deprecations.md
+++ b/doc/update/deprecations.md
@@ -1433,23 +1433,6 @@ The `merged_by` field in the [merge request API](https://docs.gitlab.com/ee/api/
-### API: `stale` status returned instead of `offline` or `not_connected`
-
-WARNING:
-This feature will be changed or removed in 15.0
-as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
-Before updating GitLab, review the details carefully to determine if you need to make any
-changes to your code, settings, or workflow.
-
-A breaking change will occur for the Runner [API](https://docs.gitlab.com/ee/api/runners.html#runners-api) endpoints in 15.0.
-
-Instead of the GitLab Runner API endpoints returning `offline` and `not_connected` for runners that have not contacted the GitLab instance in the past three months, the API endpoints will return the `stale` value, which was introduced in 14.6.
-
-**Planned removal milestone: 15.0 (2022-05-22)**
-
-
-
-
### CI/CD job name length limit
WARNING:
diff --git a/doc/update/removals.md b/doc/update/removals.md
index b796d70cea9..e1d87ef4616 100644
--- a/doc/update/removals.md
+++ b/doc/update/removals.md
@@ -30,6 +30,21 @@ For removal reviewers (Technical Writers only):
## 15.0
+### API: `stale` status returned instead of `offline` or `not_connected`
+
+WARNING:
+This feature was changed or removed in 15.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
+A breaking change was made to the Runner [API](https://docs.gitlab.com/ee/api/runners.html#runners-api) endpoints
+in 15.0.
+
+Instead of the GitLab Runner API endpoints returning `offline` and `not_connected` for runners that have not
+contacted the GitLab instance in the past three months, the API endpoints now return the `stale` value,
+which was introduced in 14.6.
+
### Background upload for object storage
WARNING:
diff --git a/doc/user/application_security/vulnerabilities/index.md b/doc/user/application_security/vulnerabilities/index.md
index 18b99e06299..87344e4ff65 100644
--- a/doc/user/application_security/vulnerabilities/index.md
+++ b/doc/user/application_security/vulnerabilities/index.md
@@ -42,7 +42,7 @@ A vulnerability's status can be one of the following:
| Dismissed | A user has seen this vulnerability and dismissed it because it is not accurate or otherwise not to be resolved. |
| Resolved | The vulnerability has been fixed or is no longer present. |
-Dismissed vulnerabilities are ignored if detected in subsequent scans. Resolved vulnerabilities that are reintroduced and detected by subsequent scans have a _new_ vulnerability record created. When an existing vulnerability is no longer detected in a project's `default` branch, you should change its status to Resolved. This ensures that if it is accidentally reintroduced in a future merge, it will be visible again as a new record. You can use the [Activity filter](../vulnerability_report/#activity-filter) to select all vulnerabilities that are no longer detected, and [change their status](../vulnerability_report#change-status-of-multiple-vulnerabilities).
+Dismissed vulnerabilities are ignored if detected in subsequent scans. Resolved vulnerabilities that are reintroduced and detected by subsequent scans have a _new_ vulnerability record created. When an existing vulnerability is no longer detected in a project's `default` branch, you should change its status to Resolved. This ensures that if it is accidentally reintroduced in a future merge, it will be visible again as a new record. You can use the [Activity filter](../vulnerability_report/#activity-filter) to select all vulnerabilities that are no longer detected, and [change their status](../vulnerability_report#change-status-of-vulnerabilities).
## Change vulnerability status
diff --git a/doc/user/application_security/vulnerability_report/index.md b/doc/user/application_security/vulnerability_report/index.md
index cda9c4eccf0..e499ddbbd6b 100644
--- a/doc/user/application_security/vulnerability_report/index.md
+++ b/doc/user/application_security/vulnerability_report/index.md
@@ -34,13 +34,18 @@ in that row:
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/6165) in GitLab 11.1.
-The project-level Vulnerability Report also contains:
+At the project level, the Vulnerability Report also contains:
- A time stamp showing when it was updated, including a link to the latest pipeline.
- The number of failures that occurred in the most recent pipeline. Select the failure
notification to view the **Failed jobs** tab of the pipeline's page.
-To access the report, navigate to **Security & Compliance > Vulnerability Report**.
+### View the project-level vulnerability report
+
+To view the project-level vulnerability report:
+
+1. On the top bar, select **Menu > Projects** and find your project.
+1. On the left sidebar, select **Security & Compliance > Vulnerability report**.
## Vulnerability Report actions
@@ -56,17 +61,22 @@ From the Vulnerability Report you can:
## Vulnerability Report filters
-You can filter the vulnerabilities table by:
+You can filter the Vulnerability Report to narrow focus on only vulnerabilities matching specific
+criteria.
+
+The available filters are:
-| Filter | Available options |
-|:---------|:------------------|
-| Status | Detected, Confirmed, Dismissed, Resolved. |
-| Severity | Critical, High, Medium, Low, Info, Unknown. |
-| Tool | For more details, see [Tool filter](#tool-filter). |
-| Project | For more details, see [Project filter](#project-filter). |
-| Activity | For more details, see [Activity filter](#activity-filter). |
+- **Status**: Detected, Confirmed, Dismissed, Resolved.
+- **Severity**: Critical, High, Medium, Low, Info, Unknown.
+- **Tool**: For more details, see [Tool filter](#tool-filter).
+- **Project**: For more details, see [Project filter](#project-filter).
+- **Activity**: For more details, see [Activity filter](#activity-filter).
+
+The filters' criteria are combined to show only vulnerabilities matching all criteria.
+An exception to this behavior is the Activity filter. For more details about how it works, see
+[Activity filter](#activity-filter).
@@ -75,7 +85,7 @@ You can filter the vulnerabilities table by:
To filter the list of vulnerabilities:
1. Select a filter.
-1. Select values from the dropdown.
+1. Select values from the dropdown list.
1. Repeat the above steps for each desired filter.
After each filter is selected:
@@ -83,11 +93,9 @@ After each filter is selected:
- The list of matching vulnerabilities is updated.
- The vulnerability severity totals are updated.
-The filters' criteria are combined to show only vulnerabilities matching all criteria.
-An exception to this behavior is the Activity filter. For more details about how it works, see
-[Activity filter](#activity-filter).
+### Tool filter
-## Tool filter
+> The third-party tool filter was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/229661) in GitLab 13.12.
The tool filter allows you to focus on vulnerabilities detected by selected tools.
@@ -95,7 +103,7 @@ When using the tool filter, you can choose:
- **All tools** (default).
- Individual GitLab-provided tools.
-- Any integrated 3rd-party tool. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/229661) in GitLab 13.12.
+- Any integrated third-party tool.
For details of each of the available tools, see [Security scanning tools](../index.md#security-scanning-tools).
@@ -103,11 +111,9 @@ For details of each of the available tools, see [Security scanning tools](../ind
The content of the Project filter depends on the current level:
-| Level | Content of the Project filter |
-|:---------------|:------------------------------|
-| Security Center | Only projects you've [added to your personal Security Center](../security_dashboard/index.md#add-projects-to-the-security-center). |
-| Group level | All projects in the group. |
-| Project level | Not applicable. |
+- **Security Center**: Only projects you've [added to your personal Security Center](../security_dashboard/index.md#add-projects-to-the-security-center).
+- **Group level**: All projects in the group.
+- **Project level**: Not applicable.
### Activity filter
@@ -119,13 +125,11 @@ all options can be selected in combination.
Selection behavior when using the Activity filter:
-| Activity selection | Results displayed |
-|:------------------------------------|:------------------|
-| All | Vulnerabilities with any Activity status (same as ignoring this filter). Selecting this deselects any other Activity filter options. |
-| No activity | Only vulnerabilities without either an associated Issue or that are no longer detected. Selecting this deselects any other Activity filter options. |
-| With issues | Only vulnerabilities with one or more associated issues. Does not include vulnerabilities that also are no longer detected. |
-| No longer detected | Only vulnerabilities that are no longer detected in the latest pipeline scan of the `default` branch. Does not include vulnerabilities with one or more associated issues. |
-| With issues and No longer detected | Only vulnerabilities that have one or more associated issues and also are no longer detected in the latest pipeline scan of the `default` branch. |
+- **All**: Vulnerabilities with any Activity status (same as ignoring this filter). Selecting this deselects any other Activity filter options.
+- **No activity**: Only vulnerabilities without either an associated issue or that are no longer detected. Selecting this deselects any other Activity filter options.
+- **With issues**: Only vulnerabilities with one or more associated issues. Does not include vulnerabilities that also are no longer detected.
+- **No longer detected**: Only vulnerabilities that are no longer detected in the latest pipeline scan of the `default` branch. Does not include vulnerabilities with one or more associated issues.
+- **With issues** and **No longer detected**: Only vulnerabilities that have one or more associated issues and also are no longer detected in the latest pipeline scan of the `default` branch.
## View details of a vulnerability
@@ -155,23 +159,32 @@ If Jira issue support is enabled, the issue link found in the Activity entry lin
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/292636) in GitLab 13.10, all statuses became selectable.
+From the Vulnerability Report you can change the status of one or more vulnerabilities.
+
To change the status of vulnerabilities in the table:
-1. Select the checkbox for each vulnerability you want to update the status of.
-1. In the dropdown that appears select the desired status, then select **Change status**.
+1. Select the checkbox beside each vulnerability you want to update the status of. To select all,
+ select the checkbox in the table header.
+1. In the **Set status** dropdown list, select the desired status.
+1. Select **Change status**.
![Project Vulnerability Report](img/project_security_dashboard_status_change_v14_2.png)
-### Change status of multiple vulnerabilities
+## Dismissing a vulnerability
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/35816) in GitLab 12.9.
+When you evaluate a vulnerability and decide it requires no more action, you can mark it
+as **Dismissed**. Dismissed vulnerabilities don't appear in the merge request security widget
+when detected in future scans.
-You can change the status of multiple vulnerabilities at once:
+When a vulnerability is dismissed, a record is made of:
-1. In the list of vulnerabilities, select the checkbox for each vulnerability you want to update.
- To select all, select the checkbox in the table header.
-1. Above the table, select a new status.
-1. Click **Change status** to save.
+- Who dismissed it.
+- Date and time when it was dismissed.
+- Optionally, a reason why it was dismissed.
+
+Vulnerability records cannot be deleted, so a permanent record always remains.
+
+If a vulnerability is dismissed in error, reverse the dismissal by changing its status.
## Export vulnerability details
diff --git a/lib/gitlab/safe_request_purger.rb b/lib/gitlab/safe_request_purger.rb
new file mode 100644
index 00000000000..b8795f1cc88
--- /dev/null
+++ b/lib/gitlab/safe_request_purger.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+module Gitlab
+ class SafeRequestPurger
+ def self.execute(args)
+ new(**args).execute
+ end
+
+ def initialize(resource_key:, resource_ids:)
+ @resource_key = resource_key
+ @resource_ids = resource_ids.uniq
+ @resource_data = {}
+ end
+
+ def execute
+ load_resource_data
+ purge_resource_ids
+ write_resource_data_to_store
+ end
+
+ private
+
+ attr_reader :resource_key, :resource_ids, :resource_data
+
+ def load_resource_data
+ @resource_data = Gitlab::SafeRequestStore.fetch(resource_key) { resource_data }
+ end
+
+ def purge_resource_ids
+ @resource_data.delete_if { |id| resource_ids.include?(id) }
+ end
+
+ def write_resource_data_to_store
+ Gitlab::SafeRequestStore.write(resource_key, resource_data)
+ end
+ end
+end
diff --git a/spec/frontend/projects/settings_service_desk/components/service_desk_setting_spec.js b/spec/frontend/projects/settings_service_desk/components/service_desk_setting_spec.js
index 57e515723e5..aac1a418142 100644
--- a/spec/frontend/projects/settings_service_desk/components/service_desk_setting_spec.js
+++ b/spec/frontend/projects/settings_service_desk/components/service_desk_setting_spec.js
@@ -165,8 +165,12 @@ describe('ServiceDeskSetting', () => {
describe('save button', () => {
it('renders a save button to save a template', () => {
wrapper = createComponent();
+ const saveButton = findButton();
- expect(findButton().text()).toContain('Save changes');
+ expect(saveButton.text()).toContain('Save changes');
+ expect(saveButton.props()).toMatchObject({
+ variant: 'confirm',
+ });
});
it('emits a save event with the chosen template when the save button is clicked', async () => {
diff --git a/spec/lib/gitlab/safe_request_purger_spec.rb b/spec/lib/gitlab/safe_request_purger_spec.rb
new file mode 100644
index 00000000000..02f3f11d469
--- /dev/null
+++ b/spec/lib/gitlab/safe_request_purger_spec.rb
@@ -0,0 +1,73 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::SafeRequestPurger do
+ let(:resource_key) { '_key_' }
+ let(:resource_ids) { ['foo'] }
+ let(:args) { { resource_key: resource_key, resource_ids: resource_ids } }
+ let(:resource_data) { { 'foo' => 'bar' } }
+
+ before do
+ Gitlab::SafeRequestStore[resource_key] = resource_data
+ end
+
+ describe '.execute', :request_store do
+ subject(:execute_instance) { described_class.execute(**args) }
+
+ it 'purges an entry from the store' do
+ execute_instance
+
+ expect(Gitlab::SafeRequestStore.fetch(resource_key)).to be_empty
+ end
+ end
+
+ describe '#execute' do
+ subject(:execute_instance) { described_class.new(**args).execute }
+
+ context 'when request store is active', :request_store do
+ it 'purges an entry from the store' do
+ execute_instance
+
+ expect(Gitlab::SafeRequestStore.fetch(resource_key)).to be_empty
+ end
+
+ context 'when there are multiple resource_ids to purge' do
+ let(:resource_data) do
+ {
+ 'foo' => 'bar',
+ 'two' => '_two_',
+ 'three' => '_three_',
+ 'four' => '_four_'
+ }
+ end
+
+ let(:resource_ids) { %w[two three] }
+
+ it 'purges an entry from the store' do
+ execute_instance
+
+ expect(Gitlab::SafeRequestStore.fetch(resource_key)).to eq resource_data.slice('foo', 'four')
+ end
+ end
+
+ context 'when there is no matching resource_ids' do
+ let(:resource_ids) { ['_bogus_resource_id_'] }
+
+ it 'purges an entry from the store' do
+ execute_instance
+
+ expect(Gitlab::SafeRequestStore.fetch(resource_key)).to eq resource_data
+ end
+ end
+ end
+
+ context 'when request store is not active' do
+ let(:resource_ids) { ['_bogus_resource_id_'] }
+
+ it 'does offer the ability to interact with data store' do
+ expect(execute_instance).to eq({})
+ end
+ end
+ end
+end
diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb
index 2983034868c..8a1dcbfbdeb 100644
--- a/spec/models/ci/runner_spec.rb
+++ b/spec/models/ci/runner_spec.rb
@@ -838,7 +838,7 @@ RSpec.describe Ci::Runner do
context 'with legacy_mode enabled' do
let(:legacy_mode) { '14.5' }
- it { is_expected.to eq(:never_contacted) }
+ it { is_expected.to eq(:stale) }
end
context 'with legacy_mode disabled' do
@@ -895,7 +895,7 @@ RSpec.describe Ci::Runner do
context 'with legacy_mode enabled' do
let(:legacy_mode) { '14.5' }
- it { is_expected.to eq(:offline) }
+ it { is_expected.to eq(:stale) }
end
context 'with legacy_mode disabled' do
@@ -905,7 +905,7 @@ RSpec.describe Ci::Runner do
end
describe '#deprecated_rest_status' do
- let(:runner) { build(:ci_runner, :instance, contacted_at: 1.second.ago) }
+ let(:runner) { create(:ci_runner, :instance, contacted_at: 1.second.ago) }
subject { runner.deprecated_rest_status }
@@ -927,10 +927,11 @@ RSpec.describe Ci::Runner do
context 'contacted long time ago' do
before do
+ runner.created_at = 1.year.ago
runner.contacted_at = 1.year.ago
end
- it { is_expected.to eq(:offline) }
+ it { is_expected.to eq(:stale) }
end
context 'inactive' do
diff --git a/spec/models/project_team_spec.rb b/spec/models/project_team_spec.rb
index 5b11f9d828a..2ddbab7779e 100644
--- a/spec/models/project_team_spec.rb
+++ b/spec/models/project_team_spec.rb
@@ -410,6 +410,22 @@ RSpec.describe ProjectTeam do
end
end
+ describe '#purge_member_access_cache_for_user_id', :request_store do
+ let(:project) { create(:project) }
+ let(:user_id) { 1 }
+ let(:resource_data) { { user_id => 50, 42 => 50 } }
+
+ before do
+ Gitlab::SafeRequestStore[project.max_member_access_for_resource_key(User)] = resource_data
+ end
+
+ it 'removes cached max access for user from store' do
+ project.team.purge_member_access_cache_for_user_id(user_id)
+
+ expect(Gitlab::SafeRequestStore[project.max_member_access_for_resource_key(User)]).to eq({ 42 => 50 })
+ end
+ end
+
describe '#member?' do
let(:group) { create(:group) }
let(:developer) { create(:user) }
diff --git a/spec/requests/api/graphql/ci/runner_spec.rb b/spec/requests/api/graphql/ci/runner_spec.rb
index 16352c4dfec..46361e49d5e 100644
--- a/spec/requests/api/graphql/ci/runner_spec.rb
+++ b/spec/requests/api/graphql/ci/runner_spec.rb
@@ -237,8 +237,8 @@ RSpec.describe 'Query.runner(id)' do
stale_runner_data = graphql_data_at(:stale_runner)
expect(stale_runner_data).to match a_hash_including(
- 'status' => 'NEVER_CONTACTED',
- 'legacyStatusWithExplicitVersion' => 'NEVER_CONTACTED',
+ 'status' => 'STALE',
+ 'legacyStatusWithExplicitVersion' => 'STALE',
'newStatus' => 'STALE'
)
diff --git a/spec/services/projects/create_service_spec.rb b/spec/services/projects/create_service_spec.rb
index 556461e6e6d..cd1e629e1d2 100644
--- a/spec/services/projects/create_service_spec.rb
+++ b/spec/services/projects/create_service_spec.rb
@@ -824,7 +824,7 @@ RSpec.describe Projects::CreateService, '#execute' do
it 'saves the project when the user has access to the label' do
expect(::Gitlab::ExternalAuthorization)
- .to receive(:access_allowed?).with(user, 'new-label', any_args) { true }
+ .to receive(:access_allowed?).with(user, 'new-label', any_args) { true }.at_least(1).time
project = create_project(user, opts.merge({ external_authorization_classification_label: 'new-label' }))