Commit 54b0a25e authored by Jonathan Schafer's avatar Jonathan Schafer Committed by David Fernandez

Add Finding Evidence Assets

DB migrations and tests added/updated

Changelog: changed
parent e20771af
# frozen_string_literal: true
# This module enables a record to be valid if any field is present
#
# Overwrite one_of_required_fields to set one of which fields must be present
module AnyFieldValidation
extend ActiveSupport::Concern
included do
validate :any_field_present
end
private
def any_field_present
return unless one_of_required_fields.all? { |field| self[field].blank? }
errors.add(:base, _("At least one field of %{one_of_required_fields} must be present") %
{ one_of_required_fields: one_of_required_fields })
end
def one_of_required_fields
raise NotImplementedError
end
end
# frozen_string_literal: true
class CreateVulnerabilityFindingEvidenceAssets < ActiveRecord::Migration[6.1]
include Gitlab::Database::MigrationHelpers
disable_ddl_transaction!
def up
create_table_with_constraints :vulnerability_finding_evidence_assets do |t|
t.timestamps_with_timezone null: false
t.references :vulnerability_finding_evidence, index: { name: 'finding_evidence_assets_on_finding_evidence_id' }, null: false, foreign_key: { on_delete: :cascade }
t.text :type
t.text :name
t.text :url
t.text_limit :type, 2048
t.text_limit :name, 2048
t.text_limit :url, 2048
end
end
def down
with_lock_retries do
drop_table :vulnerability_finding_evidence_assets
end
end
end
ee8576a7dec8e0657a3976422f74202e3f89c9a72aae64f0f75398d0c6ff5b97
\ No newline at end of file
......@@ -19132,6 +19132,28 @@ CREATE SEQUENCE vulnerability_feedback_id_seq
ALTER SEQUENCE vulnerability_feedback_id_seq OWNED BY vulnerability_feedback.id;
CREATE TABLE vulnerability_finding_evidence_assets (
id bigint NOT NULL,
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
vulnerability_finding_evidence_id bigint NOT NULL,
type text,
name text,
url text,
CONSTRAINT check_5adf5d69de CHECK ((char_length(type) <= 2048)),
CONSTRAINT check_839f29d7ca CHECK ((char_length(name) <= 2048)),
CONSTRAINT check_9272d912c0 CHECK ((char_length(url) <= 2048))
);
CREATE SEQUENCE vulnerability_finding_evidence_assets_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER SEQUENCE vulnerability_finding_evidence_assets_id_seq OWNED BY vulnerability_finding_evidence_assets.id;
CREATE TABLE vulnerability_finding_evidence_headers (
id bigint NOT NULL,
created_at timestamp with time zone NOT NULL,
......@@ -20568,6 +20590,8 @@ ALTER TABLE ONLY vulnerability_external_issue_links ALTER COLUMN id SET DEFAULT
ALTER TABLE ONLY vulnerability_feedback ALTER COLUMN id SET DEFAULT nextval('vulnerability_feedback_id_seq'::regclass);
ALTER TABLE ONLY vulnerability_finding_evidence_assets ALTER COLUMN id SET DEFAULT nextval('vulnerability_finding_evidence_assets_id_seq'::regclass);
ALTER TABLE ONLY vulnerability_finding_evidence_headers ALTER COLUMN id SET DEFAULT nextval('vulnerability_finding_evidence_headers_id_seq'::regclass);
ALTER TABLE ONLY vulnerability_finding_evidence_requests ALTER COLUMN id SET DEFAULT nextval('vulnerability_finding_evidence_requests_id_seq'::regclass);
......@@ -22286,6 +22310,9 @@ ALTER TABLE ONLY vulnerability_external_issue_links
ALTER TABLE ONLY vulnerability_feedback
ADD CONSTRAINT vulnerability_feedback_pkey PRIMARY KEY (id);
ALTER TABLE ONLY vulnerability_finding_evidence_assets
ADD CONSTRAINT vulnerability_finding_evidence_assets_pkey PRIMARY KEY (id);
ALTER TABLE ONLY vulnerability_finding_evidence_headers
ADD CONSTRAINT vulnerability_finding_evidence_headers_pkey PRIMARY KEY (id);
......@@ -22538,6 +22565,8 @@ CREATE UNIQUE INDEX epic_user_mentions_on_epic_id_and_note_id_index ON epic_user
CREATE UNIQUE INDEX epic_user_mentions_on_epic_id_index ON epic_user_mentions USING btree (epic_id) WHERE (note_id IS NULL);
CREATE INDEX finding_evidence_assets_on_finding_evidence_id ON vulnerability_finding_evidence_assets USING btree (vulnerability_finding_evidence_id);
CREATE INDEX finding_evidence_header_on_finding_evidence_request_id ON vulnerability_finding_evidence_headers USING btree (vulnerability_finding_evidence_request_id);
CREATE INDEX finding_evidence_header_on_finding_evidence_response_id ON vulnerability_finding_evidence_headers USING btree (vulnerability_finding_evidence_response_id);
......@@ -27190,6 +27219,9 @@ ALTER TABLE ONLY prometheus_alerts
ALTER TABLE ONLY term_agreements
ADD CONSTRAINT fk_rails_6ea6520e4a FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
ALTER TABLE ONLY vulnerability_finding_evidence_assets
ADD CONSTRAINT fk_rails_6edbbecba4 FOREIGN KEY (vulnerability_finding_evidence_id) REFERENCES vulnerability_finding_evidences(id) ON DELETE CASCADE;
ALTER TABLE ONLY project_compliance_framework_settings
ADD CONSTRAINT fk_rails_6f5294f16c FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
......@@ -11,6 +11,7 @@ module Vulnerabilities
has_one :response, class_name: 'Vulnerabilities::Finding::Evidence::Response', inverse_of: :evidence, foreign_key: 'vulnerability_finding_evidence_id'
has_one :supporting_message, class_name: 'Vulnerabilities::Finding::Evidence::SupportingMessage', inverse_of: :evidence, foreign_key: 'vulnerability_finding_evidence_id'
has_one :source, class_name: 'Vulnerabilities::Finding::Evidence::Source', inverse_of: :evidence, foreign_key: 'vulnerability_finding_evidence_id'
has_many :assets, class_name: 'Vulnerabilities::Finding::Evidence::Asset', inverse_of: :evidence, foreign_key: 'vulnerability_finding_evidence_id'
validates :summary, length: { maximum: 8_000_000 }
end
......
# frozen_string_literal: true
module Vulnerabilities
class Finding
class Evidence
class Asset < ApplicationRecord
include AnyFieldValidation
self.table_name = 'vulnerability_finding_evidence_assets'
belongs_to :evidence,
class_name: 'Vulnerabilities::Finding::Evidence',
inverse_of: :assets,
foreign_key: 'vulnerability_finding_evidence_id',
optional: false
validates :type, length: { maximum: 2048 }
validates :name, length: { maximum: 2048 }
validates :url, length: { maximum: 2048 }
validate :any_field_present
private
def one_of_required_fields
[:type, :name, :url]
end
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Vulnerabilities::Finding::Evidence::Asset do
it { is_expected.to belong_to(:evidence).class_name('Vulnerabilities::Finding::Evidence').inverse_of(:assets).required }
it { is_expected.to validate_length_of(:type).is_at_most(2048) }
it { is_expected.to validate_length_of(:name).is_at_most(2048) }
it { is_expected.to validate_length_of(:url).is_at_most(2048) }
describe '.any_field_present' do
let_it_be(:evidence) { build(:vulnerabilties_finding_evidence) }
let_it_be(:asset) { Vulnerabilities::Finding::Evidence::Asset.new(evidence: evidence) }
it 'is invalid if there are no fields present' do
expect(asset).not_to be_valid
end
it 'validates if there is only a type' do
asset.type = 'asset-type'
expect(asset).to be_valid
end
it 'validates if there is only a name' do
asset.type = 'asset-name'
expect(asset).to be_valid
end
it 'validates if there is only a url' do
asset.type = 'asset-url.example'
expect(asset).to be_valid
end
end
end
......@@ -8,6 +8,7 @@ RSpec.describe Vulnerabilities::Finding::Evidence do
it { is_expected.to have_one(:response).class_name('Vulnerabilities::Finding::Evidence::Response').with_foreign_key('vulnerability_finding_evidence_id').inverse_of(:evidence) }
it { is_expected.to have_one(:supporting_message).class_name('Vulnerabilities::Finding::Evidence::SupportingMessage').with_foreign_key('vulnerability_finding_evidence_id').inverse_of(:evidence) }
it { is_expected.to have_one(:source).class_name('Vulnerabilities::Finding::Evidence::Source').with_foreign_key('vulnerability_finding_evidence_id').inverse_of(:evidence) }
it { is_expected.to have_many(:assets).class_name('Vulnerabilities::Finding::Evidence::Asset').with_foreign_key('vulnerability_finding_evidence_id').inverse_of(:evidence) }
it { is_expected.to validate_length_of(:summary).is_at_most(8_000_000) }
end
......@@ -4605,6 +4605,9 @@ msgstr ""
msgid "At least one approval from a code owner is required to change files matching the respective CODEOWNER rules."
msgstr ""
msgid "At least one field of %{one_of_required_fields} must be present"
msgstr ""
msgid "At least one of group_id or project_id must be specified"
msgstr ""
......
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