Commit 60c931e6 authored by Mehmet Emin INAC's avatar Mehmet Emin INAC

Disable updating the historical vulnerability statistics by default

Historical vulnerability statistics supposed to be updated once a day
by a cronjob because updating them always for each update/insert of a
vulnerability can reduce the throughput of our worker classes and API
endpoints.

With this change, to be able to observe the side effects of disabling
the update logic of historical vulnerability statistics, we are moving
it behind a feature flag. We will remove the logic and the feature flag
eventually.

Changelog: other
EE: true
parent 4b98dc00
...@@ -479,7 +479,7 @@ four standard [pagination arguments](#connection-pagination-arguments): ...@@ -479,7 +479,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
### `Query.vulnerabilitiesCountByDay` ### `Query.vulnerabilitiesCountByDay`
Number of vulnerabilities per day for the projects on the current user's instance security dashboard. The historical number of vulnerabilities per day for the projects on the current user's instance security dashboard.
Returns [`VulnerabilitiesCountByDayConnection`](#vulnerabilitiescountbydayconnection). Returns [`VulnerabilitiesCountByDayConnection`](#vulnerabilitiescountbydayconnection).
...@@ -10004,7 +10004,7 @@ four standard [pagination arguments](#connection-pagination-arguments): ...@@ -10004,7 +10004,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
##### `Group.vulnerabilitiesCountByDay` ##### `Group.vulnerabilitiesCountByDay`
Number of vulnerabilities per day for the projects in the group and its subgroups. The historical number of vulnerabilities per day for the projects in the group and its subgroups.
Returns [`VulnerabilitiesCountByDayConnection`](#vulnerabilitiescountbydayconnection). Returns [`VulnerabilitiesCountByDayConnection`](#vulnerabilitiescountbydayconnection).
...@@ -12608,7 +12608,7 @@ four standard [pagination arguments](#connection-pagination-arguments): ...@@ -12608,7 +12608,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
##### `Project.vulnerabilitiesCountByDay` ##### `Project.vulnerabilitiesCountByDay`
Number of vulnerabilities per day for the project. The historical number of vulnerabilities per day for the project.
Returns [`VulnerabilitiesCountByDayConnection`](#vulnerabilitiescountbydayconnection). Returns [`VulnerabilitiesCountByDayConnection`](#vulnerabilitiescountbydayconnection).
......
...@@ -62,7 +62,7 @@ module EE ...@@ -62,7 +62,7 @@ module EE
field :vulnerabilities_count_by_day, field :vulnerabilities_count_by_day,
::Types::VulnerabilitiesCountByDayType.connection_type, ::Types::VulnerabilitiesCountByDayType.connection_type,
null: true, null: true,
description: 'Number of vulnerabilities per day for the projects in the group and its subgroups.', description: 'The historical number of vulnerabilities per day for the projects in the group and its subgroups.',
resolver: ::Resolvers::VulnerabilitiesCountPerDayResolver resolver: ::Resolvers::VulnerabilitiesCountPerDayResolver
field :vulnerability_grades, field :vulnerability_grades,
......
...@@ -25,7 +25,7 @@ module EE ...@@ -25,7 +25,7 @@ module EE
field :vulnerabilities_count_by_day, field :vulnerabilities_count_by_day,
::Types::VulnerabilitiesCountByDayType.connection_type, ::Types::VulnerabilitiesCountByDayType.connection_type,
null: true, null: true,
description: 'Number of vulnerabilities per day for the project.', description: 'The historical number of vulnerabilities per day for the project.',
resolver: ::Resolvers::VulnerabilitiesCountPerDayResolver resolver: ::Resolvers::VulnerabilitiesCountPerDayResolver
field :vulnerability_severities_count, ::Types::VulnerabilitySeveritiesCountType, null: true, field :vulnerability_severities_count, ::Types::VulnerabilitySeveritiesCountType, null: true,
......
...@@ -34,7 +34,7 @@ module EE ...@@ -34,7 +34,7 @@ module EE
null: true, null: true,
resolver: ::Resolvers::VulnerabilitiesCountPerDayResolver, resolver: ::Resolvers::VulnerabilitiesCountPerDayResolver,
description: <<~DESC description: <<~DESC
Number of vulnerabilities per day for the projects on the current user's instance security dashboard. The historical number of vulnerabilities per day for the projects on the current user's instance security dashboard.
DESC DESC
field :geo_node, ::Types::Geo::GeoNodeType, field :geo_node, ::Types::Geo::GeoNodeType,
......
...@@ -15,7 +15,7 @@ module Vulnerabilities ...@@ -15,7 +15,7 @@ module Vulnerabilities
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
def execute def execute
return if vulnerability_statistic.blank? return unless update_statistic?
::Vulnerabilities::HistoricalStatistic.safe_ensure_unique(retries: 1) do ::Vulnerabilities::HistoricalStatistic.safe_ensure_unique(retries: 1) do
historical_statistic = vulnerability_historical_statistics.find_or_initialize_by(date: vulnerability_statistic.updated_at) historical_statistic = vulnerability_historical_statistics.find_or_initialize_by(date: vulnerability_statistic.updated_at)
...@@ -29,6 +29,14 @@ module Vulnerabilities ...@@ -29,6 +29,14 @@ module Vulnerabilities
attr_reader :project attr_reader :project
delegate :vulnerability_statistic, :vulnerability_historical_statistics, to: :project delegate :vulnerability_statistic, :vulnerability_historical_statistics, to: :project
def update_statistic?
keep_statistics_always_consistent? && vulnerability_statistic.present?
end
def keep_statistics_always_consistent?
Feature.enabled?(:keep_historical_vulnerability_statistics_always_consistent, project)
end
end end
end end
end end
---
name: keep_historical_vulnerability_statistics_always_consistent
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68189
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/338508
milestone: '14.2'
type: development
group: group::threat insights
default_enabled: false
...@@ -24,16 +24,17 @@ RSpec.describe Vulnerabilities::HistoricalStatistics::UpdateService do ...@@ -24,16 +24,17 @@ RSpec.describe Vulnerabilities::HistoricalStatistics::UpdateService do
describe '#execute' do describe '#execute' do
subject(:update_stats) { described_class.new(project).execute } subject(:update_stats) { described_class.new(project).execute }
around do |example|
travel_to(Date.current) { example.run }
end
context 'when the `keep_historical_vulnerability_statistics_always_consistent` feature is enabled' do
context 'when the statistic is not empty' do context 'when the statistic is not empty' do
before do before do
create(:vulnerability_statistic, project: project, low: 2) create(:vulnerability_statistic, project: project, low: 2)
end end
context 'when there is already a record in the database' do context 'when there exists a record in the database' do
around do |example|
travel_to(Date.current) { example.run }
end
it 'changes the existing historical statistic entity' do it 'changes the existing historical statistic entity' do
historical_statistic = create(:vulnerability_historical_statistic, project: project, letter_grade: 'c') historical_statistic = create(:vulnerability_historical_statistic, project: project, letter_grade: 'c')
...@@ -42,7 +43,7 @@ RSpec.describe Vulnerabilities::HistoricalStatistics::UpdateService do ...@@ -42,7 +43,7 @@ RSpec.describe Vulnerabilities::HistoricalStatistics::UpdateService do
end end
end end
context 'when there is no existing record in the database' do context 'when there exists no record in the database' do
it 'creates a new record in the database' do it 'creates a new record in the database' do
expect { update_stats }.to change { Vulnerabilities::HistoricalStatistic.count }.by(1) expect { update_stats }.to change { Vulnerabilities::HistoricalStatistic.count }.by(1)
end end
...@@ -55,4 +56,38 @@ RSpec.describe Vulnerabilities::HistoricalStatistics::UpdateService do ...@@ -55,4 +56,38 @@ RSpec.describe Vulnerabilities::HistoricalStatistics::UpdateService do
end end
end end
end end
context 'when the `keep_historical_vulnerability_statistics_always_consistent` feature is disabled' do
before do
stub_feature_flags(keep_historical_vulnerability_statistics_always_consistent: false)
end
context 'when the statistic is not empty' do
before do
create(:vulnerability_statistic, project: project, low: 2)
end
context 'when there exists a record in the database' do
it 'does not change the existing historical statistic entity' do
historical_statistic = create(:vulnerability_historical_statistic, project: project, letter_grade: 'c')
expect { update_stats }.to not_change { historical_statistic.reload.letter_grade }.from('c')
.and not_change { historical_statistic.reload.low }.from(0)
end
end
context 'when there exists no record in the database' do
it 'does not create a new record in the database' do
expect { update_stats }.not_to change { Vulnerabilities::HistoricalStatistic.count }
end
end
end
context 'when the statistic is empty' do
it 'does not create any historical statistic entity' do
expect { update_stats }.not_to change { Vulnerabilities::Statistic.count }
end
end
end
end
end end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment