Commit c954e9a9 authored by Mehmet Emin INAC's avatar Mehmet Emin INAC Committed by Yannis Roussos

Introduce Vulnerability::Remediation entity

- Add the Vulnerability::Remediation model to store remediation
  data in a structured way
- Add the pivot model Vulnerability::FindingRemediation to establish
  many to many relationship between finding and remediation entities
- Add database migrations to create remediation related tables
parent 702c4a12
---
title: Create `vulnerability_findings_remediations` and `vulnerability_remediations`
tables
merge_request: 47166
author:
type: added
# frozen_string_literal: true
class CreateVulnerabilityRemediationsTable < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
create_table :vulnerability_remediations, if_not_exists: true do |t|
t.timestamps_with_timezone
t.integer :file_store, limit: 2
t.text :summary, null: false
t.text :file, null: false
end
add_text_limit :vulnerability_remediations, :summary, 200
add_text_limit :vulnerability_remediations, :file, 255
end
def down
drop_table :vulnerability_remediations
end
end
# frozen_string_literal: true
class CreateVulnerabilityFindingsRemediationsJoinTable < ActiveRecord::Migration[6.0]
DOWNTIME = false
def change
create_table :vulnerability_findings_remediations do |t|
t.references :vulnerability_occurrence, index: false, foreign_key: { on_delete: :cascade }
t.references :vulnerability_remediation, index: { name: 'index_vulnerability_findings_remediations_on_remediation_id' }, foreign_key: { on_delete: :cascade }
t.timestamps_with_timezone
t.index [:vulnerability_occurrence_id, :vulnerability_remediation_id], unique: true, name: 'index_vulnerability_findings_remediations_on_unique_keys'
end
end
end
27ee3c5429dba139e6c300961172c4f90d25397e3d1e13d0654e049b63ac3325
\ No newline at end of file
bdbf3cf39228c9b65b02391a9aa030bdeb06aa3fc9955e2fd53bd784bea37b66
\ No newline at end of file
...@@ -17190,6 +17190,23 @@ CREATE SEQUENCE vulnerability_finding_links_id_seq ...@@ -17190,6 +17190,23 @@ CREATE SEQUENCE vulnerability_finding_links_id_seq
ALTER SEQUENCE vulnerability_finding_links_id_seq OWNED BY vulnerability_finding_links.id; ALTER SEQUENCE vulnerability_finding_links_id_seq OWNED BY vulnerability_finding_links.id;
CREATE TABLE vulnerability_findings_remediations (
id bigint NOT NULL,
vulnerability_occurrence_id bigint,
vulnerability_remediation_id bigint,
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL
);
CREATE SEQUENCE vulnerability_findings_remediations_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER SEQUENCE vulnerability_findings_remediations_id_seq OWNED BY vulnerability_findings_remediations.id;
CREATE TABLE vulnerability_historical_statistics ( CREATE TABLE vulnerability_historical_statistics (
id bigint NOT NULL, id bigint NOT NULL,
created_at timestamp with time zone NOT NULL, created_at timestamp with time zone NOT NULL,
...@@ -17316,6 +17333,26 @@ CREATE SEQUENCE vulnerability_occurrences_id_seq ...@@ -17316,6 +17333,26 @@ CREATE SEQUENCE vulnerability_occurrences_id_seq
ALTER SEQUENCE vulnerability_occurrences_id_seq OWNED BY vulnerability_occurrences.id; ALTER SEQUENCE vulnerability_occurrences_id_seq OWNED BY vulnerability_occurrences.id;
CREATE TABLE vulnerability_remediations (
id bigint NOT NULL,
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
file_store smallint,
summary text NOT NULL,
file text NOT NULL,
CONSTRAINT check_ac0ccabff3 CHECK ((char_length(summary) <= 200)),
CONSTRAINT check_fe3325e3ba CHECK ((char_length(file) <= 255))
);
CREATE SEQUENCE vulnerability_remediations_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER SEQUENCE vulnerability_remediations_id_seq OWNED BY vulnerability_remediations.id;
CREATE TABLE vulnerability_scanners ( CREATE TABLE vulnerability_scanners (
id bigint NOT NULL, id bigint NOT NULL,
created_at timestamp with time zone NOT NULL, created_at timestamp with time zone NOT NULL,
...@@ -18298,6 +18335,8 @@ ALTER TABLE ONLY vulnerability_feedback ALTER COLUMN id SET DEFAULT nextval('vul ...@@ -18298,6 +18335,8 @@ ALTER TABLE ONLY vulnerability_feedback ALTER COLUMN id SET DEFAULT nextval('vul
ALTER TABLE ONLY vulnerability_finding_links ALTER COLUMN id SET DEFAULT nextval('vulnerability_finding_links_id_seq'::regclass); ALTER TABLE ONLY vulnerability_finding_links ALTER COLUMN id SET DEFAULT nextval('vulnerability_finding_links_id_seq'::regclass);
ALTER TABLE ONLY vulnerability_findings_remediations ALTER COLUMN id SET DEFAULT nextval('vulnerability_findings_remediations_id_seq'::regclass);
ALTER TABLE ONLY vulnerability_historical_statistics ALTER COLUMN id SET DEFAULT nextval('vulnerability_historical_statistics_id_seq'::regclass); ALTER TABLE ONLY vulnerability_historical_statistics ALTER COLUMN id SET DEFAULT nextval('vulnerability_historical_statistics_id_seq'::regclass);
ALTER TABLE ONLY vulnerability_identifiers ALTER COLUMN id SET DEFAULT nextval('vulnerability_identifiers_id_seq'::regclass); ALTER TABLE ONLY vulnerability_identifiers ALTER COLUMN id SET DEFAULT nextval('vulnerability_identifiers_id_seq'::regclass);
...@@ -18310,6 +18349,8 @@ ALTER TABLE ONLY vulnerability_occurrence_pipelines ALTER COLUMN id SET DEFAULT ...@@ -18310,6 +18349,8 @@ ALTER TABLE ONLY vulnerability_occurrence_pipelines ALTER COLUMN id SET DEFAULT
ALTER TABLE ONLY vulnerability_occurrences ALTER COLUMN id SET DEFAULT nextval('vulnerability_occurrences_id_seq'::regclass); ALTER TABLE ONLY vulnerability_occurrences ALTER COLUMN id SET DEFAULT nextval('vulnerability_occurrences_id_seq'::regclass);
ALTER TABLE ONLY vulnerability_remediations ALTER COLUMN id SET DEFAULT nextval('vulnerability_remediations_id_seq'::regclass);
ALTER TABLE ONLY vulnerability_scanners ALTER COLUMN id SET DEFAULT nextval('vulnerability_scanners_id_seq'::regclass); ALTER TABLE ONLY vulnerability_scanners ALTER COLUMN id SET DEFAULT nextval('vulnerability_scanners_id_seq'::regclass);
ALTER TABLE ONLY vulnerability_statistics ALTER COLUMN id SET DEFAULT nextval('vulnerability_statistics_id_seq'::regclass); ALTER TABLE ONLY vulnerability_statistics ALTER COLUMN id SET DEFAULT nextval('vulnerability_statistics_id_seq'::regclass);
...@@ -19753,6 +19794,9 @@ ALTER TABLE ONLY vulnerability_feedback ...@@ -19753,6 +19794,9 @@ ALTER TABLE ONLY vulnerability_feedback
ALTER TABLE ONLY vulnerability_finding_links ALTER TABLE ONLY vulnerability_finding_links
ADD CONSTRAINT vulnerability_finding_links_pkey PRIMARY KEY (id); ADD CONSTRAINT vulnerability_finding_links_pkey PRIMARY KEY (id);
ALTER TABLE ONLY vulnerability_findings_remediations
ADD CONSTRAINT vulnerability_findings_remediations_pkey PRIMARY KEY (id);
ALTER TABLE ONLY vulnerability_historical_statistics ALTER TABLE ONLY vulnerability_historical_statistics
ADD CONSTRAINT vulnerability_historical_statistics_pkey PRIMARY KEY (id); ADD CONSTRAINT vulnerability_historical_statistics_pkey PRIMARY KEY (id);
...@@ -19771,6 +19815,9 @@ ALTER TABLE ONLY vulnerability_occurrence_pipelines ...@@ -19771,6 +19815,9 @@ ALTER TABLE ONLY vulnerability_occurrence_pipelines
ALTER TABLE ONLY vulnerability_occurrences ALTER TABLE ONLY vulnerability_occurrences
ADD CONSTRAINT vulnerability_occurrences_pkey PRIMARY KEY (id); ADD CONSTRAINT vulnerability_occurrences_pkey PRIMARY KEY (id);
ALTER TABLE ONLY vulnerability_remediations
ADD CONSTRAINT vulnerability_remediations_pkey PRIMARY KEY (id);
ALTER TABLE ONLY vulnerability_scanners ALTER TABLE ONLY vulnerability_scanners
ADD CONSTRAINT vulnerability_scanners_pkey PRIMARY KEY (id); ADD CONSTRAINT vulnerability_scanners_pkey PRIMARY KEY (id);
...@@ -22229,6 +22276,10 @@ CREATE INDEX index_vulnerability_feedback_on_merge_request_id ON vulnerability_f ...@@ -22229,6 +22276,10 @@ CREATE INDEX index_vulnerability_feedback_on_merge_request_id ON vulnerability_f
CREATE INDEX index_vulnerability_feedback_on_pipeline_id ON vulnerability_feedback USING btree (pipeline_id); CREATE INDEX index_vulnerability_feedback_on_pipeline_id ON vulnerability_feedback USING btree (pipeline_id);
CREATE INDEX index_vulnerability_findings_remediations_on_remediation_id ON vulnerability_findings_remediations USING btree (vulnerability_remediation_id);
CREATE UNIQUE INDEX index_vulnerability_findings_remediations_on_unique_keys ON vulnerability_findings_remediations USING btree (vulnerability_occurrence_id, vulnerability_remediation_id);
CREATE INDEX index_vulnerability_historical_statistics_on_date_and_id ON vulnerability_historical_statistics USING btree (date, id); CREATE INDEX index_vulnerability_historical_statistics_on_date_and_id ON vulnerability_historical_statistics USING btree (date, id);
CREATE UNIQUE INDEX index_vulnerability_identifiers_on_project_id_and_fingerprint ON vulnerability_identifiers USING btree (project_id, fingerprint); CREATE UNIQUE INDEX index_vulnerability_identifiers_on_project_id_and_fingerprint ON vulnerability_identifiers USING btree (project_id, fingerprint);
...@@ -23508,6 +23559,9 @@ ALTER TABLE ONLY project_alerting_settings ...@@ -23508,6 +23559,9 @@ ALTER TABLE ONLY project_alerting_settings
ALTER TABLE ONLY dast_site_validations ALTER TABLE ONLY dast_site_validations
ADD CONSTRAINT fk_rails_285c617324 FOREIGN KEY (dast_site_token_id) REFERENCES dast_site_tokens(id) ON DELETE CASCADE; ADD CONSTRAINT fk_rails_285c617324 FOREIGN KEY (dast_site_token_id) REFERENCES dast_site_tokens(id) ON DELETE CASCADE;
ALTER TABLE ONLY vulnerability_findings_remediations
ADD CONSTRAINT fk_rails_28a8d0cf93 FOREIGN KEY (vulnerability_occurrence_id) REFERENCES vulnerability_occurrences(id) ON DELETE CASCADE;
ALTER TABLE ONLY resource_state_events ALTER TABLE ONLY resource_state_events
ADD CONSTRAINT fk_rails_29af06892a FOREIGN KEY (issue_id) REFERENCES issues(id) ON DELETE CASCADE; ADD CONSTRAINT fk_rails_29af06892a FOREIGN KEY (issue_id) REFERENCES issues(id) ON DELETE CASCADE;
...@@ -23868,6 +23922,9 @@ ALTER TABLE ONLY web_hook_logs ...@@ -23868,6 +23922,9 @@ ALTER TABLE ONLY web_hook_logs
ALTER TABLE ONLY jira_imports ALTER TABLE ONLY jira_imports
ADD CONSTRAINT fk_rails_675d38c03b FOREIGN KEY (label_id) REFERENCES labels(id) ON DELETE SET NULL; ADD CONSTRAINT fk_rails_675d38c03b FOREIGN KEY (label_id) REFERENCES labels(id) ON DELETE SET NULL;
ALTER TABLE ONLY vulnerability_findings_remediations
ADD CONSTRAINT fk_rails_681c85ae0f FOREIGN KEY (vulnerability_remediation_id) REFERENCES vulnerability_remediations(id) ON DELETE CASCADE;
ALTER TABLE ONLY resource_iteration_events ALTER TABLE ONLY resource_iteration_events
ADD CONSTRAINT fk_rails_6830c13ac1 FOREIGN KEY (merge_request_id) REFERENCES merge_requests(id) ON DELETE CASCADE; ADD CONSTRAINT fk_rails_6830c13ac1 FOREIGN KEY (merge_request_id) REFERENCES merge_requests(id) ON DELETE CASCADE;
......
...@@ -28,6 +28,9 @@ module Vulnerabilities ...@@ -28,6 +28,9 @@ module Vulnerabilities
has_many :finding_links, class_name: 'Vulnerabilities::FindingLink', inverse_of: :finding, foreign_key: 'vulnerability_occurrence_id' has_many :finding_links, class_name: 'Vulnerabilities::FindingLink', inverse_of: :finding, foreign_key: 'vulnerability_occurrence_id'
has_many :finding_remediations, class_name: 'Vulnerabilities::FindingRemediation', inverse_of: :finding, foreign_key: 'vulnerability_occurrence_id'
has_many :remediations, through: :finding_remediations
has_many :finding_pipelines, class_name: 'Vulnerabilities::FindingPipeline', inverse_of: :finding, foreign_key: 'occurrence_id' has_many :finding_pipelines, class_name: 'Vulnerabilities::FindingPipeline', inverse_of: :finding, foreign_key: 'occurrence_id'
has_many :pipelines, through: :finding_pipelines, class_name: 'Ci::Pipeline' has_many :pipelines, through: :finding_pipelines, class_name: 'Ci::Pipeline'
......
# frozen_string_literal: true
# This is a join model between the `Finding` and `Remediation` models.
module Vulnerabilities
class FindingRemediation < ApplicationRecord
self.table_name = 'vulnerability_findings_remediations'
belongs_to :finding, class_name: 'Vulnerabilities::Finding', inverse_of: :finding_remediations, foreign_key: 'vulnerability_occurrence_id', optional: false
belongs_to :remediation, class_name: 'Vulnerabilities::Remediation', inverse_of: :finding_remediations, foreign_key: 'vulnerability_remediation_id', optional: false
end
end
# frozen_string_literal: true
module Vulnerabilities
class Remediation < ApplicationRecord
include FileStoreMounter
self.table_name = 'vulnerability_remediations'
has_many :finding_remediations, class_name: 'Vulnerabilities::FindingRemediation', inverse_of: :remediation, foreign_key: 'vulnerability_remediation_id'
has_many :findings, through: :finding_remediations
mount_file_store_uploader AttachmentUploader
validates :summary, presence: true, length: { maximum: 200 }
validates :file, presence: true
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Vulnerabilities::FindingRemediation do
it { is_expected.to belong_to(:finding).class_name('Vulnerabilities::Finding').required }
it { is_expected.to belong_to(:remediation).class_name('Vulnerabilities::Remediation').required }
end
...@@ -17,6 +17,8 @@ RSpec.describe Vulnerabilities::Finding do ...@@ -17,6 +17,8 @@ RSpec.describe Vulnerabilities::Finding do
it { is_expected.to have_many(:identifiers).class_name('Vulnerabilities::Identifier') } it { is_expected.to have_many(:identifiers).class_name('Vulnerabilities::Identifier') }
it { is_expected.to have_many(:finding_identifiers).class_name('Vulnerabilities::FindingIdentifier').with_foreign_key('occurrence_id') } it { is_expected.to have_many(:finding_identifiers).class_name('Vulnerabilities::FindingIdentifier').with_foreign_key('occurrence_id') }
it { is_expected.to have_many(:finding_links).class_name('Vulnerabilities::FindingLink').with_foreign_key('vulnerability_occurrence_id') } it { is_expected.to have_many(:finding_links).class_name('Vulnerabilities::FindingLink').with_foreign_key('vulnerability_occurrence_id') }
it { is_expected.to have_many(:finding_remediations).class_name('Vulnerabilities::FindingRemediation').with_foreign_key('vulnerability_occurrence_id') }
it { is_expected.to have_many(:remediations).through(:finding_remediations) }
end end
describe 'validations' do describe 'validations' do
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Vulnerabilities::Remediation do
it { is_expected.to have_many(:finding_remediations).class_name('Vulnerabilities::FindingRemediation') }
it { is_expected.to have_many(:findings).through(:finding_remediations) }
it { is_expected.to validate_presence_of(:summary) }
it { is_expected.to validate_presence_of(:file) }
it { is_expected.to validate_length_of(:summary).is_at_most(200) }
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