Commit d79129b4 authored by Jonathan Schafer's avatar Jonathan Schafer Committed by Steve Abrams

Add finding evidence header

Add migration
Add model
Add/update tests
Update request/response models

Changelog: added
parent b569ae00
# frozen_string_literal: true
class CreateVulnerabilityFindingEvidenceHeaders < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
create_table_with_constraints :vulnerability_finding_evidence_headers do |t|
t.timestamps_with_timezone null: false
t.references :vulnerability_finding_evidence_request, index: { name: 'finding_evidence_header_on_finding_evidence_request_id' }, null: true, foreign_key: { on_delete: :cascade }
t.references :vulnerability_finding_evidence_response, index: { name: 'finding_evidence_header_on_finding_evidence_response_id' }, null: true, foreign_key: { on_delete: :cascade }
t.text :name, null: false
t.text :value, null: false
t.text_limit :name, 255
t.text_limit :value, 8192
end
end
def down
with_lock_retries do
drop_table :vulnerability_finding_evidence_headers
end
end
end
18fdca797ea7f3a60ce5b421bec7af1ea0b0b73fbf6e1c23592acbc9d13a0a52
\ No newline at end of file
......@@ -18913,6 +18913,27 @@ CREATE SEQUENCE vulnerability_feedback_id_seq
ALTER SEQUENCE vulnerability_feedback_id_seq OWNED BY vulnerability_feedback.id;
CREATE TABLE vulnerability_finding_evidence_headers (
id bigint NOT NULL,
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
vulnerability_finding_evidence_request_id bigint,
vulnerability_finding_evidence_response_id bigint,
name text NOT NULL,
value text NOT NULL,
CONSTRAINT check_01d21e8d92 CHECK ((char_length(name) <= 255)),
CONSTRAINT check_3f9011f903 CHECK ((char_length(value) <= 8192))
);
CREATE SEQUENCE vulnerability_finding_evidence_headers_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER SEQUENCE vulnerability_finding_evidence_headers_id_seq OWNED BY vulnerability_finding_evidence_headers.id;
CREATE TABLE vulnerability_finding_evidence_requests (
id bigint NOT NULL,
created_at timestamp with time zone NOT NULL,
......@@ -20288,6 +20309,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_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);
ALTER TABLE ONLY vulnerability_finding_evidence_responses ALTER COLUMN id SET DEFAULT nextval('vulnerability_finding_evidence_responses_id_seq'::regclass);
......@@ -21970,6 +21993,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_headers
ADD CONSTRAINT vulnerability_finding_evidence_headers_pkey PRIMARY KEY (id);
ALTER TABLE ONLY vulnerability_finding_evidence_requests
ADD CONSTRAINT vulnerability_finding_evidence_requests_pkey PRIMARY KEY (id);
......@@ -22210,6 +22236,10 @@ 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_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);
CREATE INDEX finding_evidence_requests_on_finding_evidence_id ON vulnerability_finding_evidence_requests USING btree (vulnerability_finding_evidence_id);
CREATE INDEX finding_evidence_responses_on_finding_evidences_id ON vulnerability_finding_evidence_responses USING btree (vulnerability_finding_evidence_id);
......@@ -26697,6 +26727,9 @@ ALTER TABLE ONLY vulnerability_findings_remediations
ALTER TABLE ONLY resource_iteration_events
ADD CONSTRAINT fk_rails_6830c13ac1 FOREIGN KEY (merge_request_id) REFERENCES merge_requests(id) ON DELETE CASCADE;
ALTER TABLE ONLY vulnerability_finding_evidence_headers
ADD CONSTRAINT fk_rails_683b8e000c FOREIGN KEY (vulnerability_finding_evidence_response_id) REFERENCES vulnerability_finding_evidence_responses(id) ON DELETE CASCADE;
ALTER TABLE ONLY geo_hashed_storage_migrated_events
ADD CONSTRAINT fk_rails_687ed7d7c5 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
......@@ -27267,6 +27300,9 @@ ALTER TABLE ONLY operations_strategies_user_lists
ALTER TABLE ONLY issue_tracker_data
ADD CONSTRAINT fk_rails_ccc0840427 FOREIGN KEY (service_id) REFERENCES services(id) ON DELETE CASCADE;
ALTER TABLE ONLY vulnerability_finding_evidence_headers
ADD CONSTRAINT fk_rails_ce7f121a03 FOREIGN KEY (vulnerability_finding_evidence_request_id) REFERENCES vulnerability_finding_evidence_requests(id) ON DELETE CASCADE;
ALTER TABLE ONLY resource_milestone_events
ADD CONSTRAINT fk_rails_cedf8cce4d FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL;
# frozen_string_literal: true
module Vulnerabilities
class Finding
class Evidence
class Header < ApplicationRecord
self.table_name = 'vulnerability_finding_evidence_headers'
belongs_to :request, class_name: 'Vulnerabilities::Finding::Evidence::Request', inverse_of: :headers, foreign_key: 'vulnerability_finding_evidence_request_id'
belongs_to :response, class_name: 'Vulnerabilities::Finding::Evidence::Response', inverse_of: :headers, foreign_key: 'vulnerability_finding_evidence_response_id'
validates :name, length: { maximum: 255 }
validates :value, length: { maximum: 8192 }
validate :request_or_response_is_set
validate :request_and_response_cannot_be_set
private
def request_or_response_is_set
errors.add(:header, _('Header must be associated with a request or response')) unless request.present? || response.present?
end
def request_and_response_cannot_be_set
errors.add(:header, _('Header cannot be associated with both a request and a response')) if request.present? && response.present?
end
end
end
end
end
......@@ -7,6 +7,7 @@ module Vulnerabilities
self.table_name = 'vulnerability_finding_evidence_requests'
belongs_to :evidence, class_name: 'Vulnerabilities::Finding::Evidence', inverse_of: :request, foreign_key: 'vulnerability_finding_evidence_id', optional: false
has_many :headers, class_name: 'Vulnerabilities::Finding::Evidence::Header', inverse_of: :request, foreign_key: 'vulnerability_finding_evidence_request_id'
validates :method, length: { maximum: 32 }
validates :url, length: { maximum: 2048 }
......
......@@ -7,6 +7,7 @@ module Vulnerabilities
self.table_name = 'vulnerability_finding_evidence_responses'
belongs_to :evidence, class_name: 'Vulnerabilities::Finding::Evidence', inverse_of: :response, foreign_key: 'vulnerability_finding_evidence_id', optional: false
has_many :headers, class_name: 'Vulnerabilities::Finding::Evidence::Header', inverse_of: :response, foreign_key: 'vulnerability_finding_evidence_response_id'
validates :reason_phrase, length: { maximum: 2048 }
validates :body, length: { maximum: 2048 }
......
# frozen_string_literal: true
FactoryBot.define do
factory :vulnerabilties_finding_evidence, class: 'Vulnerabilities::Finding::Evidence' do
summary { 'Evidence summary' }
end
end
# frozen_string_literal: true
FactoryBot.define do
factory :vulnerabilties_finding_evidence_header, class: 'Vulnerabilities::Finding::Evidence::Header' do
name { 'HEADER-NAME' }
value { 'header-value' }
end
end
# frozen_string_literal: true
FactoryBot.define do
factory :vulnerabilties_finding_evidence_request, class: 'Vulnerabilities::Finding::Evidence::Request' do
url { 'https://www.example.com' }
body { 'Request body' }
end
end
# frozen_string_literal: true
FactoryBot.define do
factory :vulnerabilties_finding_evidence_response, class: 'Vulnerabilities::Finding::Evidence::Response' do
reason_phrase { 'Response reason' }
body { 'Response body' }
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Vulnerabilities::Finding::Evidence::Header do
it { is_expected.to belong_to(:request).class_name('Vulnerabilities::Finding::Evidence::Request').inverse_of(:headers).optional }
it { is_expected.to belong_to(:response).class_name('Vulnerabilities::Finding::Evidence::Response').inverse_of(:headers).optional }
it { is_expected.to validate_length_of(:name).is_at_most(255) }
it { is_expected.to validate_length_of(:value).is_at_most(8192) }
describe '.request_or_response_is_set' do
let(:header) { build(:vulnerabilties_finding_evidence_header) }
it 'is invalid if there is no request or response' do
expect(header).not_to be_valid
end
it 'validates if there is a response' do
header.response = build(:vulnerabilties_finding_evidence_response)
expect(header).to be_valid
end
it 'validates if there is a request' do
header.request = build(:vulnerabilties_finding_evidence_request)
expect(header).to be_valid
end
it 'is invalid if there is a request and a response' do
header.request = build(:vulnerabilties_finding_evidence_request)
header.response = build(:vulnerabilties_finding_evidence_response)
expect(header).not_to be_valid
end
end
end
......@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe Vulnerabilities::Finding::Evidence::Request do
it { is_expected.to belong_to(:evidence).class_name('Vulnerabilities::Finding::Evidence').inverse_of(:request).required }
it { is_expected.to have_many(:headers).class_name('Vulnerabilities::Finding::Evidence::Header').with_foreign_key('vulnerability_finding_evidence_request_id').inverse_of(:request) }
it { is_expected.to validate_length_of(:method).is_at_most(32) }
it { is_expected.to validate_length_of(:url).is_at_most(2048) }
......
......@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe Vulnerabilities::Finding::Evidence::Response do
it { is_expected.to belong_to(:evidence).class_name('Vulnerabilities::Finding::Evidence').inverse_of(:response).required }
it { is_expected.to have_many(:headers).class_name('Vulnerabilities::Finding::Evidence::Header').with_foreign_key('vulnerability_finding_evidence_response_id').inverse_of(:response) }
it { is_expected.to validate_length_of(:reason_phrase).is_at_most(2048) }
it { is_expected.to validate_length_of(:body).is_at_most(2048) }
......
......@@ -16289,6 +16289,9 @@ msgstr ""
msgid "Hashed storage can't be disabled anymore for new projects"
msgstr ""
msgid "Header cannot be associated with both a request and a response"
msgstr ""
msgid "Header logo"
msgstr ""
......@@ -16301,6 +16304,9 @@ msgstr ""
msgid "Header message"
msgstr ""
msgid "Header must be associated with a request or response"
msgstr ""
msgid "Headings"
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