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' }))