Commit cd913c66 authored by Alan (Maciej) Paruszewski's avatar Alan (Maciej) Paruszewski Committed by Heinrich Lee Yu

Add Vulnerability Historical Statistics

This change adds new model to store historical vulnerability statistics
data.
parent 990a39f7
# frozen_string_literal: true
class CreateVulnerabilityHistoricalStatistics < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
INDEX_NAME = 'index_vuln_historical_statistics_on_project_id_and_date'
DOWNTIME = false
def up
with_lock_retries do
create_table :vulnerability_historical_statistics do |t|
t.timestamps_with_timezone null: false
t.references :project, null: false, index: false, foreign_key: { on_delete: :cascade }
t.integer :total, default: 0, null: false
t.integer :critical, default: 0, null: false
t.integer :high, default: 0, null: false
t.integer :medium, default: 0, null: false
t.integer :low, default: 0, null: false
t.integer :unknown, default: 0, null: false
t.integer :info, default: 0, null: false
t.date :date, null: false
t.integer :letter_grade, limit: 1, null: false
t.index [:project_id, :date], unique: true, name: INDEX_NAME
end
end
end
def down
with_lock_retries do
drop_table :vulnerability_historical_statistics
end
end
end
......@@ -16077,6 +16077,31 @@ CREATE SEQUENCE public.vulnerability_feedback_id_seq
ALTER SEQUENCE public.vulnerability_feedback_id_seq OWNED BY public.vulnerability_feedback.id;
CREATE TABLE public.vulnerability_historical_statistics (
id bigint NOT NULL,
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
project_id bigint NOT NULL,
total integer DEFAULT 0 NOT NULL,
critical integer DEFAULT 0 NOT NULL,
high integer DEFAULT 0 NOT NULL,
medium integer DEFAULT 0 NOT NULL,
low integer DEFAULT 0 NOT NULL,
unknown integer DEFAULT 0 NOT NULL,
info integer DEFAULT 0 NOT NULL,
date date NOT NULL,
letter_grade smallint NOT NULL
);
CREATE SEQUENCE public.vulnerability_historical_statistics_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER SEQUENCE public.vulnerability_historical_statistics_id_seq OWNED BY public.vulnerability_historical_statistics.id;
CREATE TABLE public.vulnerability_identifiers (
id bigint NOT NULL,
created_at timestamp with time zone NOT NULL,
......@@ -17068,6 +17093,8 @@ ALTER TABLE ONLY public.vulnerability_exports ALTER COLUMN id SET DEFAULT nextva
ALTER TABLE ONLY public.vulnerability_feedback ALTER COLUMN id SET DEFAULT nextval('public.vulnerability_feedback_id_seq'::regclass);
ALTER TABLE ONLY public.vulnerability_historical_statistics ALTER COLUMN id SET DEFAULT nextval('public.vulnerability_historical_statistics_id_seq'::regclass);
ALTER TABLE ONLY public.vulnerability_identifiers ALTER COLUMN id SET DEFAULT nextval('public.vulnerability_identifiers_id_seq'::regclass);
ALTER TABLE ONLY public.vulnerability_issue_links ALTER COLUMN id SET DEFAULT nextval('public.vulnerability_issue_links_id_seq'::regclass);
......@@ -18332,6 +18359,9 @@ ALTER TABLE ONLY public.vulnerability_exports
ALTER TABLE ONLY public.vulnerability_feedback
ADD CONSTRAINT vulnerability_feedback_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.vulnerability_historical_statistics
ADD CONSTRAINT vulnerability_historical_statistics_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.vulnerability_identifiers
ADD CONSTRAINT vulnerability_identifiers_pkey PRIMARY KEY (id);
......@@ -20523,6 +20553,8 @@ CREATE INDEX index_users_star_projects_on_project_id ON public.users_star_projec
CREATE UNIQUE INDEX index_users_star_projects_on_user_id_and_project_id ON public.users_star_projects USING btree (user_id, project_id);
CREATE UNIQUE INDEX index_vuln_historical_statistics_on_project_id_and_date ON public.vulnerability_historical_statistics USING btree (project_id, date);
CREATE INDEX index_vulnerabilities_on_author_id ON public.vulnerabilities USING btree (author_id);
CREATE INDEX index_vulnerabilities_on_confirmed_by_id ON public.vulnerabilities USING btree (confirmed_by_id);
......@@ -22090,6 +22122,9 @@ ALTER TABLE ONLY public.list_user_preferences
ALTER TABLE ONLY public.project_custom_attributes
ADD CONSTRAINT fk_rails_719c3dccc5 FOREIGN KEY (project_id) REFERENCES public.projects(id) ON DELETE CASCADE;
ALTER TABLE ONLY public.vulnerability_historical_statistics
ADD CONSTRAINT fk_rails_72b73ed023 FOREIGN KEY (project_id) REFERENCES public.projects(id) ON DELETE CASCADE;
ALTER TABLE ONLY public.slack_integrations
ADD CONSTRAINT fk_rails_73db19721a FOREIGN KEY (service_id) REFERENCES public.services(id) ON DELETE CASCADE;
......@@ -23867,6 +23902,7 @@ COPY "schema_migrations" (version) FROM STDIN;
20200713071042
20200713141854
20200713152443
20200715135130
20200715202659
20200716044023
20200716120419
......
......@@ -62,6 +62,7 @@ module EE
# https://gitlab.com/gitlab-org/gitlab/issues/10252#terminology
has_many :vulnerabilities
has_many :vulnerability_feedback, class_name: 'Vulnerabilities::Feedback'
has_many :vulnerability_historical_statistics, class_name: 'Vulnerabilities::HistoricalStatistic'
has_many :vulnerability_findings, class_name: 'Vulnerabilities::Occurrence' do
def lock_for_confirmation!(id)
where(vulnerability_id: nil).lock.find(id)
......
# frozen_string_literal: true
module Vulnerabilities
class HistoricalStatistic < ApplicationRecord
self.table_name = 'vulnerability_historical_statistics'
belongs_to :project, optional: false
validates :date, presence: true
validates :letter_grade, presence: true
validates :total, numericality: { greater_than_or_equal_to: 0 }
validates :critical, numericality: { greater_than_or_equal_to: 0 }
validates :high, numericality: { greater_than_or_equal_to: 0 }
validates :medium, numericality: { greater_than_or_equal_to: 0 }
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 }
enum letter_grade: Vulnerabilities::Statistic.letter_grades
end
end
---
title: Add Vulnerabilities::HistoricalStatistic model
merge_request: 36955
author:
type: added
# frozen_string_literal: true
FactoryBot.define do
factory :vulnerability_historical_statistic, class: 'Vulnerabilities::HistoricalStatistic' do
project
letter_grade { 'a' }
date { Date.today }
end
end
......@@ -45,6 +45,7 @@ RSpec.describe Project do
it { is_expected.to have_many(:upstream_projects) }
it { is_expected.to have_many(:downstream_project_subscriptions) }
it { is_expected.to have_many(:downstream_projects) }
it { is_expected.to have_many(:vulnerability_historical_statistics).class_name('Vulnerabilities::HistoricalStatistic') }
it { is_expected.to have_one(:github_service) }
it { is_expected.to have_many(:project_aliases) }
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Vulnerabilities::HistoricalStatistic do
describe 'associations' do
it { is_expected.to belong_to(:project).required(true) }
end
describe 'validations' do
it { is_expected.to validate_presence_of(:date) }
it { is_expected.to validate_presence_of(:letter_grade) }
it { is_expected.to validate_numericality_of(:total).is_greater_than_or_equal_to(0) }
it { is_expected.to validate_numericality_of(:critical).is_greater_than_or_equal_to(0) }
it { is_expected.to validate_numericality_of(:high).is_greater_than_or_equal_to(0) }
it { is_expected.to validate_numericality_of(:medium).is_greater_than_or_equal_to(0) }
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 define_enum_for(:letter_grade).with_values(%i(a b c d f)) }
end
end
......@@ -515,6 +515,7 @@ project:
- webex_teams_service
- build_report_results
- vulnerability_statistic
- vulnerability_historical_statistics
award_emoji:
- awardable
- user
......
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