diff --git a/app/workers/personal_access_tokens/expiring_worker.rb b/app/workers/personal_access_tokens/expiring_worker.rb index 492fdf9776c..9e754dde22c 100644 --- a/app/workers/personal_access_tokens/expiring_worker.rb +++ b/app/workers/personal_access_tokens/expiring_worker.rb @@ -52,7 +52,12 @@ module PersonalAccessTokens deliver_user_notifications(user, token_names) - expiring_user_tokens.update_all(expire_notification_delivered: true) + # we are in the process of deprecating expire_notification_delivered column + # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/166683 + expiring_user_tokens.update_all( + expire_notification_delivered: true, + seven_days_notification_sent_at: Time.current + ) end end end @@ -102,7 +107,13 @@ module PersonalAccessTokens tokens_with_delivered_notifications = tokens .where.not(user_id: project_bot_ids_without_resource | project_bot_ids_with_failed_delivery) - tokens_with_delivered_notifications.update_all(expire_notification_delivered: true) + + # we are in the process of deprecating expire_notification_delivered column + # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/166683 + tokens_with_delivered_notifications.update_all( + expire_notification_delivered: true, + seven_days_notification_sent_at: Time.current + ) notifications_delivered += tokens_with_delivered_notifications.count end diff --git a/config/initializers/wikicloth_redos_patch.rb b/config/initializers/wikicloth_redos_patch.rb index 501a4084edc..98afe000e5b 100644 --- a/config/initializers/wikicloth_redos_patch.rb +++ b/config/initializers/wikicloth_redos_patch.rb @@ -209,7 +209,7 @@ module WikiCloth when "nowiki" return self.element_content when "a" - if self.element_attributes['href'] =~ /:\/\// + if /:\/\//.match?(self.element_attributes['href']) return @options[:link_handler].external_link(self.element_attributes['href'], self.element_content) elsif self.element_attributes['href'].nil? || self.element_attributes['href'] =~ /^\s*([\?\/])/ # if a element has no href attribute, or href starts with / or ? diff --git a/db/docs/batched_background_migrations/backfill_personal_access_token_seven_days_notification_sent.yml b/db/docs/batched_background_migrations/backfill_personal_access_token_seven_days_notification_sent.yml new file mode 100644 index 00000000000..d09291f1d37 --- /dev/null +++ b/db/docs/batched_background_migrations/backfill_personal_access_token_seven_days_notification_sent.yml @@ -0,0 +1,10 @@ +--- +migration_job_name: BackfillPersonalAccessTokenSevenDaysNotificationSent +description: Backfill seven_days_notification_sent_at column using data from expires_at column in personal_access_tokens table. +feature_category: system_access +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/165592 +milestone: '17.5' +queued_migration_version: 20240909222743 +# Replace with the approximate date you think it's best to ensure the completion of this BBM. +finalize_after: '2024-10-24' +finalized_by: # version of the migration that finalized this BBM diff --git a/db/post_migrate/20240909222539_create_temp_index_for_backfilling_pat_notifications.rb b/db/post_migrate/20240909222539_create_temp_index_for_backfilling_pat_notifications.rb new file mode 100644 index 00000000000..399c81bbc34 --- /dev/null +++ b/db/post_migrate/20240909222539_create_temp_index_for_backfilling_pat_notifications.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +class CreateTempIndexForBackfillingPatNotifications < Gitlab::Database::Migration[2.2] + milestone '17.5' + + disable_ddl_transaction! + + INDEX_NAME = 'tmp_index_pats_on_notification_columns_and_expires_at' + INDEX_CONDITION = 'expire_notification_delivered IS TRUE ' \ + 'AND seven_days_notification_sent_at IS NULL ' \ + 'AND expires_at IS NOT NULL' + + def up + # to be removed once BackfillPersonalAccessTokenSevenDaysNotificationSent is finalized + # https://gitlab.com/gitlab-org/gitlab/-/issues/485856 + add_concurrent_index :personal_access_tokens, :id, where: INDEX_CONDITION, name: INDEX_NAME + end + + def down + remove_concurrent_index_by_name :personal_access_tokens, INDEX_NAME + end +end diff --git a/db/post_migrate/20240909222743_queue_backfill_personal_access_token_seven_days_notification_sent.rb b/db/post_migrate/20240909222743_queue_backfill_personal_access_token_seven_days_notification_sent.rb new file mode 100644 index 00000000000..4f0999a99b8 --- /dev/null +++ b/db/post_migrate/20240909222743_queue_backfill_personal_access_token_seven_days_notification_sent.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +class QueueBackfillPersonalAccessTokenSevenDaysNotificationSent < Gitlab::Database::Migration[2.2] + milestone '17.5' + restrict_gitlab_migration gitlab_schema: :gitlab_main + + MIGRATION = "BackfillPersonalAccessTokenSevenDaysNotificationSent" + DELAY_INTERVAL = 2.minutes + BATCH_SIZE = 1000 + SUB_BATCH_SIZE = 100 + + def up + queue_batched_background_migration( + MIGRATION, + :personal_access_tokens, + :id, + job_interval: DELAY_INTERVAL, + batch_size: BATCH_SIZE, + sub_batch_size: SUB_BATCH_SIZE + ) + end + + def down + delete_batched_background_migration(MIGRATION, :personal_access_tokens, :id, []) + end +end diff --git a/db/schema_migrations/20240909222539 b/db/schema_migrations/20240909222539 new file mode 100644 index 00000000000..9372b4702a9 --- /dev/null +++ b/db/schema_migrations/20240909222539 @@ -0,0 +1 @@ +8eba9f08402dee5cf285ca26e521c3ec1f4e8b1bd94ec57bfdf21c91597f6584 \ No newline at end of file diff --git a/db/schema_migrations/20240909222743 b/db/schema_migrations/20240909222743 new file mode 100644 index 00000000000..cff840e8cc6 --- /dev/null +++ b/db/schema_migrations/20240909222743 @@ -0,0 +1 @@ +33feb1432b6e33edf61831495df67bc064e30653c2501bfc94bc2881dbe917e7 \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 6488b0fd1f2..838adf0408a 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -31446,6 +31446,8 @@ CREATE INDEX tmp_index_on_vulnerabilities_non_dismissed ON vulnerabilities USING CREATE INDEX tmp_index_packages_dependencies_on_id_without_project_id ON packages_dependencies USING btree (id) WHERE (project_id IS NULL); +CREATE INDEX tmp_index_pats_on_notification_columns_and_expires_at ON personal_access_tokens USING btree (id) WHERE ((expire_notification_delivered IS TRUE) AND (seven_days_notification_sent_at IS NULL) AND (expires_at IS NOT NULL)); + CREATE INDEX tmp_index_project_statistics_cont_registry_size ON project_statistics USING btree (project_id) WHERE (container_registry_size = 0); CREATE INDEX tmp_index_vulnerability_overlong_title_html ON vulnerabilities USING btree (id) WHERE (length(title_html) > 800); diff --git a/doc/user/clusters/agent/vulnerabilities.md b/doc/user/clusters/agent/vulnerabilities.md index 37ec95a0e13..34b994737b4 100644 --- a/doc/user/clusters/agent/vulnerabilities.md +++ b/doc/user/clusters/agent/vulnerabilities.md @@ -115,6 +115,14 @@ The CRON expression is evaluated in [UTC](https://www.timeanddate.com/worldclock You can view the complete schema within the [scan execution policy documentation](../../application_security/policies/scan_execution_policies.md#scan-execution-policies-schema). +## OCS vulnerability resolution for multi cluster configuration + +To ensure accurate vulnerability tracking with OCS, you should create a separate GitLab project with OCS enabled for each cluster. If you have multiple clusters, be sure to use one project for each cluster. + +OCS resolves vulnerabilities that are no longer found in your cluster after each scan by comparing the current scan vulnerabilities with those previously detected. Any vulnerabilities from earlier scans that are no longer present in the current scan are resolved for the GitLab project. + +If multiple clusters are configured in the same project, an OCS scan in one cluster (for example, Project A) would resolve previously detected vulnerabilities from another cluster (for example, Project B), leading to incorrect vulnerability reporting. + ## Configure scanner resource requirements By default the scanner pod's default resource requirements are: diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 709e0aac2e4..0bfb79b0470 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -181,7 +181,7 @@ module API def find_pipeline(id) return unless id - if id.to_s =~ INTEGER_ID_REGEX + if INTEGER_ID_REGEX.match?(id.to_s) ::Ci::Pipeline.find_by(id: id) end end @@ -210,7 +210,7 @@ module API def find_group(id, organization: nil) collection = organization.present? ? Group.in_organization(organization) : Group.all - if id.to_s =~ INTEGER_ID_REGEX + if INTEGER_ID_REGEX.match?(id.to_s) collection.find_by(id: id) else collection.find_by_full_path(id) @@ -250,7 +250,7 @@ module API # find_namespace returns the namespace regardless of user access level on the namespace # rubocop: disable CodeReuse/ActiveRecord def find_namespace(id) - if id.to_s =~ INTEGER_ID_REGEX + if INTEGER_ID_REGEX.match?(id.to_s) Namespace.without_project_namespaces.find_by(id: id) else find_namespace_by_path(id) diff --git a/lib/api/helpers/common_helpers.rb b/lib/api/helpers/common_helpers.rb index 265e9ffcdbd..8f86387ee2e 100644 --- a/lib/api/helpers/common_helpers.rb +++ b/lib/api/helpers/common_helpers.rb @@ -27,7 +27,7 @@ module API options[:route_options][:params].map do |key, val| param_type = val[:type] # Search for parameters with Array types (e.g. "[String]", "[Integer]", etc.) - if param_type =~ %r{\[\w*\]} + if %r{\[\w*\]}.match?(param_type) key end end.compact.to_set diff --git a/lib/api/validations/validators/bulk_imports.rb b/lib/api/validations/validators/bulk_imports.rb index 5b1ee81596b..e06bc3dcea5 100644 --- a/lib/api/validations/validators/bulk_imports.rb +++ b/lib/api/validations/validators/bulk_imports.rb @@ -6,7 +6,7 @@ module API module BulkImports class DestinationSlugPath < Grape::Validations::Validators::Base def validate_param!(attr_name, params) - return if params[attr_name] =~ Gitlab::Regex.oci_repository_path_regex + return if Gitlab::Regex.oci_repository_path_regex.match?(params[attr_name]) raise Grape::Exceptions::Validation.new( params: [@scope.full_name(attr_name)], diff --git a/lib/banzai/color_parser.rb b/lib/banzai/color_parser.rb index 6d01d51955c..59284ab5159 100644 --- a/lib/banzai/color_parser.rb +++ b/lib/banzai/color_parser.rb @@ -40,7 +40,7 @@ module Banzai # # Returns the recognized color String or nil if none was found. def self.parse(text) - text if COLOR_FORMAT =~ text + text if COLOR_FORMAT.match?(text) end end end diff --git a/lib/banzai/filter/ascii_doc_sanitization_filter.rb b/lib/banzai/filter/ascii_doc_sanitization_filter.rb index cd49dead0d1..67fd5b8289f 100644 --- a/lib/banzai/filter/ascii_doc_sanitization_filter.rb +++ b/lib/banzai/filter/ascii_doc_sanitization_filter.rb @@ -77,10 +77,10 @@ module Banzai return unless node.name == 'a' || node.name == 'div' || SECTION_HEADINGS.any?(node.name) return unless node.has_attribute?('id') - return if node['id'] =~ PREFIXED_ID_PATTERN + return if PREFIXED_ID_PATTERN.match?(node['id']) if (pattern = FOOTNOTE_LINK_ID_PATTERNS[node.name.to_sym]) - return if node['id'] =~ pattern + return if node['id']&.match?(pattern) end node.remove_attribute('id') diff --git a/lib/banzai/filter/references/abstract_reference_filter.rb b/lib/banzai/filter/references/abstract_reference_filter.rb index c8e2932bfd7..ea3dd002ccc 100644 --- a/lib/banzai/filter/references/abstract_reference_filter.rb +++ b/lib/banzai/filter/references/abstract_reference_filter.rb @@ -157,7 +157,7 @@ module Banzai next end - if link =~ link_pattern_anchor + if link_pattern_anchor.match?(link) replace_link_node_with_href(node, index, link) do object_link_filter(link, link_pattern_anchor, link_content: inner_html, link_reference: true) end diff --git a/lib/banzai/filter/references/reference_filter.rb b/lib/banzai/filter/references/reference_filter.rb index 39dc5b7b9a6..12b3b6e5918 100644 --- a/lib/banzai/filter/references/reference_filter.rb +++ b/lib/banzai/filter/references/reference_filter.rb @@ -53,7 +53,7 @@ module Banzai end elsif element_node?(node) yield_valid_link(node) do |link, inner_html| - if link =~ ref_pattern_start + if ref_pattern_start.match?(link) replace_link_node_with_href(node, index, link) do object_link_filter(link, ref_pattern_start, link_content: inner_html) end diff --git a/lib/bulk_imports/path_normalization.rb b/lib/bulk_imports/path_normalization.rb index e673b22969b..57988d08829 100644 --- a/lib/bulk_imports/path_normalization.rb +++ b/lib/bulk_imports/path_normalization.rb @@ -5,7 +5,7 @@ module BulkImports private def normalize_path(path) - return path.downcase if path =~ Gitlab::Regex.oci_repository_path_regex + return path.downcase if Gitlab::Regex.oci_repository_path_regex.match?(path) path = path.parameterize.downcase diff --git a/lib/feature/definition.rb b/lib/feature/definition.rb index d61033b0b6c..1308d457be8 100644 --- a/lib/feature/definition.rb +++ b/lib/feature/definition.rb @@ -40,7 +40,7 @@ module Feature raise Feature::InvalidFeatureFlagError, "Feature flag is missing name" end - unless VALID_FEATURE_NAME =~ name + unless VALID_FEATURE_NAME.match?(name) raise Feature::InvalidFeatureFlagError, "Feature flag '#{name}' is invalid" end diff --git a/lib/gitlab/background_migration/backfill_personal_access_token_seven_days_notification_sent.rb b/lib/gitlab/background_migration/backfill_personal_access_token_seven_days_notification_sent.rb new file mode 100644 index 00000000000..9ef69f57344 --- /dev/null +++ b/lib/gitlab/background_migration/backfill_personal_access_token_seven_days_notification_sent.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +module Gitlab + module BackgroundMigration + class BackfillPersonalAccessTokenSevenDaysNotificationSent < BatchedMigrationJob + operation_name :backfill_personal_access_token_seven_days_notification_sent + + # rubocop:disable CodeReuse/ActiveRecord -- guidelines says query methods are okay to use here + scope_to ->(relation) do + relation.where(expire_notification_delivered: true, seven_days_notification_sent_at: nil) + .where.not(expires_at: nil) + end + # rubocop:enable CodeReuse/ActiveRecord + + feature_category :system_access + + def perform + each_sub_batch do |sub_batch| + sub_batch.update_all("seven_days_notification_sent_at = (expires_at - interval '7 days')") + end + end + end + end +end diff --git a/lib/tasks/gitlab/update_templates.rake b/lib/tasks/gitlab/update_templates.rake index 2f79f89700a..51b4707c9b1 100644 --- a/lib/tasks/gitlab/update_templates.rake +++ b/lib/tasks/gitlab/update_templates.rake @@ -155,7 +155,7 @@ namespace :gitlab do # - Dir.entries returns also the entries '.' and '..' def remove_unneeded_files(directory, regex) Dir.foreach(directory) do |file| - FileUtils.rm_rf(File.join(directory, file)) unless file =~ regex + FileUtils.rm_rf(File.join(directory, file)) unless regex.match?(file) end end diff --git a/lib/uploaded_file.rb b/lib/uploaded_file.rb index af817bfc046..32416db99e3 100644 --- a/lib/uploaded_file.rb +++ b/lib/uploaded_file.rb @@ -92,7 +92,7 @@ class UploadedFile name = name.tr("\\", "/") # work-around for IE name = ::File.basename(name) name = name.gsub(CarrierWave::SanitizedFile.sanitize_regexp, "_") - name = "_#{name}" if name =~ /\A\.+\z/ + name = "_#{name}" if /\A\.+\z/.match?(name) name = "unnamed" if name.empty? name.mb_chars.to_s end diff --git a/qa/qa/flow/integrations/slack.rb b/qa/qa/flow/integrations/slack.rb index c6562a181bd..341bbffa6ff 100644 --- a/qa/qa/flow/integrations/slack.rb +++ b/qa/qa/flow/integrations/slack.rb @@ -41,7 +41,7 @@ module QA chat_page.messages.last.text =~ /connect your GitLab account|404 not found!/i end - break(true) if chat_page.messages.last.text =~ /404 not found!/i + break(true) if /404 not found!/i.match?(chat_page.messages.last.text) chat_page.click_connect_account_link diff --git a/qa/qa/git/location.rb b/qa/qa/git/location.rb index 9ac97a66e53..16d0959ae2c 100644 --- a/qa/qa/git/location.rb +++ b/qa/qa/git/location.rb @@ -14,7 +14,7 @@ module QA def initialize(git_uri) @git_uri = git_uri @uri = - if git_uri =~ %r{\A(?:ssh|http|https)://} + if %r{\A(?:ssh|http|https)://}.match?(git_uri) URI.parse(git_uri) else *rest, path = git_uri.split(':') diff --git a/qa/qa/resource/api_fabricator.rb b/qa/qa/resource/api_fabricator.rb index 03ccda8afd0..62f4926d430 100644 --- a/qa/qa/resource/api_fabricator.rb +++ b/qa/qa/resource/api_fabricator.rb @@ -117,7 +117,7 @@ module QA body = extract_graphql_body(graphql_response) unless graphql_response.code == HTTP_STATUS_OK && (body[:errors].nil? || body[:errors].empty?) - action = post_body =~ /mutation {\s+destroy/ ? 'Deletion' : 'Fabrication' + action = /mutation {\s+destroy/.match?(post_body) ? 'Deletion' : 'Fabrication' raise(ResourceFabricationFailedError, <<~MSG.strip) #{action} of #{self.class.name} using the API failed (#{graphql_response.code}) with `#{graphql_response}`. #{QA::Support::Loglinking.failure_metadata(graphql_response.headers[:x_request_id])} diff --git a/qa/qa/runtime/search.rb b/qa/qa/runtime/search.rb index a0ad84285be..6c09e3815ad 100644 --- a/qa/qa/runtime/search.rb +++ b/qa/qa/runtime/search.rb @@ -113,7 +113,7 @@ module QA def verify_search_engine_ok(search_term) response = get_response('commits', search_term) - if response.code.to_s =~ /5[0-9][0-9]/ + if /5[0-9][0-9]/.match?(response.code.to_s) raise ElasticSearchServerError, "elasticsearch attempt returned code #{response.code}. Check that search was conducted on the appropriate url and port." end end diff --git a/qa/qa/service/cluster_provider/k3d.rb b/qa/qa/service/cluster_provider/k3d.rb index 4c2347c3409..57b08410f3f 100644 --- a/qa/qa/service/cluster_provider/k3d.rb +++ b/qa/qa/service/cluster_provider/k3d.rb @@ -53,7 +53,7 @@ module QA def fetch_kubeconfig retry_until do config = `k3d get-kubeconfig --name #{cluster_name}`.chomp - config if config =~ /kubeconfig.yaml/ + config if /kubeconfig.yaml/.match?(config) end end diff --git a/qa/qa/specs/features/api/3_create/merge_request/view_merge_requests_spec.rb b/qa/qa/specs/features/api/3_create/merge_request/view_merge_requests_spec.rb index b6f65670c1f..25d4f6c3344 100644 --- a/qa/qa/specs/features/api/3_create/merge_request/view_merge_requests_spec.rb +++ b/qa/qa/specs/features/api/3_create/merge_request/view_merge_requests_spec.rb @@ -4,17 +4,13 @@ require 'net/http' module QA RSpec.describe 'Create' do - describe 'Merge Requests', product_group: :code_review, - quarantine: { - issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/483173', - type: :investigating - } do + describe 'Merge Requests', product_group: :code_review do let(:address) { Runtime::Address.new(:gitlab, '') } context 'with a malformed URL' do let(:path) { %(/-/merge_requests?sort=created_date&state= #{test['testcase']} in file: #{test['id']} with title: diff --git a/scripts/trigger-build.rb b/scripts/trigger-build.rb index 882bff45811..e37109630c1 100755 --- a/scripts/trigger-build.rb +++ b/scripts/trigger-build.rb @@ -232,7 +232,7 @@ module Trigger raw_version = super # if the version matches semver format, treat it as a tag and prepend `v` - if raw_version =~ Regexp.compile(/^\d+\.\d+\.\d+(-rc\d+)?(-ee)?$/) + if Regexp.compile(/^\d+\.\d+\.\d+(-rc\d+)?(-ee)?$/).match?(raw_version) "v#{raw_version}" else raw_version diff --git a/sidekiq_cluster/cli.rb b/sidekiq_cluster/cli.rb index e3045c17768..2760eecb5e1 100644 --- a/sidekiq_cluster/cli.rb +++ b/sidekiq_cluster/cli.rb @@ -72,7 +72,7 @@ module Gitlab available_queues = queues_from_routing_rules.empty? ? DEFAULT_QUEUES : [*queues_from_routing_rules, 'mailers'].freeze queue_groups = argv.map do |queues| - if queues =~ /[\r\n]/ + if /[\r\n]/.match?(queues) raise CommandError, 'The queue arguments cannot contain newlines' end diff --git a/spec/lib/gitlab/background_migration/backfill_personal_access_token_seven_days_notification_sent_spec.rb b/spec/lib/gitlab/background_migration/backfill_personal_access_token_seven_days_notification_sent_spec.rb new file mode 100644 index 00000000000..73ba0144f79 --- /dev/null +++ b/spec/lib/gitlab/background_migration/backfill_personal_access_token_seven_days_notification_sent_spec.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::BackgroundMigration::BackfillPersonalAccessTokenSevenDaysNotificationSent, feature_category: :system_access do + let(:pats_table) { table(:personal_access_tokens) } + let(:users) { table(:users) } + let(:organizations) { table(:organizations) } + + let!(:organization) { organizations.create!(name: 'default org', path: 'dflt') } + let!(:user) { users.create!(email: 'capybara@example.com', encrypted_password: 'abc123', projects_limit: 2) } + let!(:pat_to_update) do + pats_table.create!(name: 'notified token', expire_notification_delivered: true, expires_at: Date.current, + user_id: user.id, organization_id: organization.id) + end + + let!(:seven_days_notified) do + pats_table.create!(name: 'seven days token', expire_notification_delivered: true, expires_at: Date.current, + seven_days_notification_sent_at: Time.current - 1.day, user_id: user.id, organization_id: organization.id) + end + + let!(:not_notified_pat) do + pats_table.create!(name: 'not notified token', expires_at: Date.current + 1, user_id: user.id, + organization_id: organization.id) + end + + let!(:no_expiry_pat) do + pats_table.create!(name: 'no expiry token', expire_notification_delivered: true, user_id: user.id, + organization_id: organization.id) + end + + describe '#perform' do + subject(:perform_migration) do + described_class.new( + start_id: pats_table.first.id, + end_id: pats_table.last.id, + batch_table: :personal_access_tokens, + batch_column: :id, + sub_batch_size: pats_table.count, + pause_ms: 0, + connection: ActiveRecord::Base.connection + ).perform + end + + it 'backfills seven_days_notification_sent_at field', :freeze_time do + expect(pat_to_update.reload.seven_days_notification_sent_at).to be_nil + expect(seven_days_notified.reload.seven_days_notification_sent_at).to eq(Time.current - 1.day) + expect(not_notified_pat.reload.seven_days_notification_sent_at).to be_nil + expect(no_expiry_pat.reload.seven_days_notification_sent_at).to be_nil + + perform_migration + + # db updates do not use the same timezone as Rails; default to UTC + db_updated_time = Time.utc(Time.current.year, Time.current.month, Time.current.day) - 7.days + expect(pat_to_update.reload.seven_days_notification_sent_at).to eq(db_updated_time) + + expect(seven_days_notified.reload.seven_days_notification_sent_at).to eq(Time.current - 1.day) + expect(not_notified_pat.reload.seven_days_notification_sent_at).to be_nil + expect(no_expiry_pat.reload.seven_days_notification_sent_at).to be_nil + end + end +end diff --git a/spec/migrations/20240909222743_queue_backfill_personal_access_token_seven_days_notification_sent_spec.rb b/spec/migrations/20240909222743_queue_backfill_personal_access_token_seven_days_notification_sent_spec.rb new file mode 100644 index 00000000000..1a53799b723 --- /dev/null +++ b/spec/migrations/20240909222743_queue_backfill_personal_access_token_seven_days_notification_sent_spec.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe QueueBackfillPersonalAccessTokenSevenDaysNotificationSent, feature_category: :system_access do + let!(:batched_migration) { described_class::MIGRATION } + + it 'schedules a new batched migration' do + reversible_migration do |migration| + migration.before -> { + expect(batched_migration).not_to have_scheduled_batched_migration + } + + migration.after -> { + expect(batched_migration).to have_scheduled_batched_migration( + table_name: :personal_access_tokens, + column_name: :id, + interval: described_class::DELAY_INTERVAL, + batch_size: described_class::BATCH_SIZE, + sub_batch_size: described_class::SUB_BATCH_SIZE + ) + } + end + end +end diff --git a/spec/routing/group_routing_spec.rb b/spec/routing/group_routing_spec.rb index ba50e8eccc1..5282c30787e 100644 --- a/spec/routing/group_routing_spec.rb +++ b/spec/routing/group_routing_spec.rb @@ -75,7 +75,7 @@ RSpec.shared_examples 'groups routing' do end end -RSpec.describe "Groups", "routing" do +RSpec.describe "Groups", "routing", feature_category: :groups_and_projects do context 'complex group path with dot' do include_examples 'groups routing' do let(:group_path) { 'complex.group-namegit' } diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb index 7da8ecb7600..e00366af15b 100644 --- a/spec/routing/project_routing_spec.rb +++ b/spec/routing/project_routing_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'project routing' do +RSpec.describe 'project routing', feature_category: :groups_and_projects do let(:base_params) { { namespace_id: 'gitlab', project_id: 'gitlabhq' } } before do diff --git a/spec/workers/personal_access_tokens/expiring_worker_spec.rb b/spec/workers/personal_access_tokens/expiring_worker_spec.rb index 3065d7c12f4..ef2291a0630 100644 --- a/spec/workers/personal_access_tokens/expiring_worker_spec.rb +++ b/spec/workers/personal_access_tokens/expiring_worker_spec.rb @@ -41,6 +41,10 @@ RSpec.describe PersonalAccessTokens::ExpiringWorker, type: :worker, feature_cate expect { worker.perform }.to change { expiring_token.reload.expire_notification_delivered }.from(false).to(true) end + it 'marks the notification as delivered with new column', :freeze_time do + expect { worker.perform }.to change { expiring_token.reload.seven_days_notification_sent_at }.from(nil).to(Time.current) + end + it 'avoids N+1 queries', :use_sql_query_cache do control = ActiveRecord::QueryRecorder.new(skip_cached: false) { worker.perform }