diff --git a/db/migrate/20251022005737_add_not_empty_constraint_to_vulnerability_statistics_traversal_ids.rb b/db/migrate/20251022005737_add_not_empty_constraint_to_vulnerability_statistics_traversal_ids.rb new file mode 100644 index 0000000000000000000000000000000000000000..8f020710afcedc928e7fb04b0814b9c2f43678fe --- /dev/null +++ b/db/migrate/20251022005737_add_not_empty_constraint_to_vulnerability_statistics_traversal_ids.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +class AddNotEmptyConstraintToVulnerabilityStatisticsTraversalIds < Gitlab::Database::Migration[2.3] + disable_ddl_transaction! + milestone '18.6' + + def up + add_check_constraint( + :vulnerability_statistics, + 'cardinality(traversal_ids) > 0', + 'check_vulnerability_statistics_traversal_ids_not_empty', + validate: false + ) + end + + def down + remove_check_constraint( + :vulnerability_statistics, + 'check_vulnerability_statistics_traversal_ids_not_empty' + ) + end +end diff --git a/db/schema_migrations/20251022005737 b/db/schema_migrations/20251022005737 new file mode 100644 index 0000000000000000000000000000000000000000..3d73b79418c12b3e350a7915297b08880af410f4 --- /dev/null +++ b/db/schema_migrations/20251022005737 @@ -0,0 +1 @@ +9faaf92dda2f7b3e7f77e5701eeec91e908c77761955e295922b5b18eb4a45eb \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index b5bdd311d8bfe26837cecb23a7ed051d3bf3e977..6a1685493722baf4db861d0ba49fe5be8e23b0de 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -33300,6 +33300,9 @@ ALTER TABLE project_type_ci_runner_machines ALTER TABLE project_type_ci_runners ADD CONSTRAINT check_organization_id_nullness CHECK ((organization_id IS NOT NULL)) NOT VALID; +ALTER TABLE vulnerability_statistics + ADD CONSTRAINT check_vulnerability_statistics_traversal_ids_not_empty CHECK ((cardinality(traversal_ids) > 0)) NOT VALID; + ALTER TABLE ONLY ci_build_needs ADD CONSTRAINT ci_build_needs_pkey PRIMARY KEY (id); diff --git a/ee/app/models/vulnerabilities/statistic.rb b/ee/app/models/vulnerabilities/statistic.rb index 71ba18f5ccbdaee10f5ed260cfaa14704fabd362..4c710316cee013a048f6930fcda3e71866897dd0 100644 --- a/ee/app/models/vulnerabilities/statistic.rb +++ b/ee/app/models/vulnerabilities/statistic.rb @@ -36,6 +36,7 @@ class Statistic < ::SecApplicationRecord validates :low, numericality: { greater_than_or_equal_to: 0 } validates :unknown, numericality: { greater_than_or_equal_to: 0 } validates :info, numericality: { greater_than_or_equal_to: 0 } + validates :traversal_ids, presence: true, length: { minimum: 1 } before_save :assign_letter_grade diff --git a/ee/spec/factories/vulnerabilities/statistics.rb b/ee/spec/factories/vulnerabilities/statistics.rb index bceb246ff12f6e95d142e0bb34136c54aedaf0f3..e9fe1154ad242c961bbe4c7536bd5fbc51c86859 100644 --- a/ee/spec/factories/vulnerabilities/statistics.rb +++ b/ee/spec/factories/vulnerabilities/statistics.rb @@ -3,11 +3,11 @@ FactoryBot.define do factory :vulnerability_statistic, class: 'Vulnerabilities::Statistic' do project + traversal_ids { project.namespace.traversal_ids } initialize_with { Vulnerabilities::Statistic.find_or_initialize_by(project_id: project.id) } after(:build) do |vulnerability_statistic, _| vulnerability_statistic.archived = vulnerability_statistic.project&.archived - vulnerability_statistic.traversal_ids = vulnerability_statistic.project&.namespace&.traversal_ids vulnerability_statistic.total = [ vulnerability_statistic.low, vulnerability_statistic.medium, diff --git a/ee/spec/models/vulnerabilities/statistic_spec.rb b/ee/spec/models/vulnerabilities/statistic_spec.rb index 1cc1752c97c5849c9a776967baa217f7fb107bfe..e7a1fe36dfff11f30274535bd1e8f5883b1784ff 100644 --- a/ee/spec/models/vulnerabilities/statistic_spec.rb +++ b/ee/spec/models/vulnerabilities/statistic_spec.rb @@ -16,6 +16,9 @@ it { is_expected.to validate_numericality_of(:low).is_greater_than_or_equal_to(0) } it { is_expected.to validate_numericality_of(:unknown).is_greater_than_or_equal_to(0) } it { is_expected.to validate_numericality_of(:info).is_greater_than_or_equal_to(0) } + it { is_expected.to validate_presence_of(:traversal_ids) } + it { is_expected.to validate_length_of(:traversal_ids).is_at_least(1) } + it { is_expected.to define_enum_for(:letter_grade).with_values(%i[a b c d f]) } end diff --git a/spec/lib/gitlab/background_migration/backfill_archived_and_traversal_ids_to_vulnerability_statistics_spec.rb b/spec/lib/gitlab/background_migration/backfill_archived_and_traversal_ids_to_vulnerability_statistics_spec.rb index e2a4a0613c67336a90d664eb10c4011254c4c356..0ced0812cd6267f75f79a9d54dcbabfa532a3161 100644 --- a/spec/lib/gitlab/background_migration/backfill_archived_and_traversal_ids_to_vulnerability_statistics_spec.rb +++ b/spec/lib/gitlab/background_migration/backfill_archived_and_traversal_ids_to_vulnerability_statistics_spec.rb @@ -46,7 +46,7 @@ before do [project, other_project].each do |p| - create_vulnerability_statistic(project_id: p.id) + create_vulnerability_statistic(project: p) end end @@ -62,9 +62,10 @@ end end - def create_vulnerability_statistic(project_id:) + def create_vulnerability_statistic(project:) + namespace = namespaces.find(project.namespace_id) vulnerability_statistics.create!( - project_id: project_id, + project_id: project.id, total: 0, critical: 0, high: 0, @@ -74,6 +75,7 @@ def create_vulnerability_statistic(project_id:) info: 0, letter_grade: 0, created_at: Time.current, + traversal_ids: namespace.traversal_ids, updated_at: Time.current ) end