Commit f1e18d56 authored by Mikołaj Wawrzyniak's avatar Mikołaj Wawrzyniak

Merge branch '343280-evidence-metadata' into 'master'

Use finding_evidence over raw_metadata

See merge request gitlab-org/gitlab!75140
parents 57aa5386 adcf3d51
...@@ -39,7 +39,7 @@ module Vulnerabilities ...@@ -39,7 +39,7 @@ module Vulnerabilities
has_many :vulnerability_flags, class_name: 'Vulnerabilities::Flag', inverse_of: :finding, foreign_key: 'vulnerability_occurrence_id' has_many :vulnerability_flags, class_name: 'Vulnerabilities::Flag', inverse_of: :finding, foreign_key: 'vulnerability_occurrence_id'
has_one :evidence, class_name: 'Vulnerabilities::Finding::Evidence', inverse_of: :finding, foreign_key: 'vulnerability_occurrence_id' has_one :finding_evidence, class_name: 'Vulnerabilities::Finding::Evidence', inverse_of: :finding, foreign_key: 'vulnerability_occurrence_id'
serialize :config_options, Serializers::Json # rubocop:disable Cop/ActiveRecordSerialize serialize :config_options, Serializers::Json # rubocop:disable Cop/ActiveRecordSerialize
...@@ -285,12 +285,14 @@ module Vulnerabilities ...@@ -285,12 +285,14 @@ module Vulnerabilities
end end
def evidence def evidence
evidence_data = finding_evidence.present? ? finding_evidence.data : metadata.dig('evidence')
{ {
summary: metadata.dig('evidence', 'summary'), summary: evidence_data&.dig('summary'),
request: build_evidence_request(metadata.dig('evidence', 'request')), request: build_evidence_request(evidence_data&.dig('request')),
response: build_evidence_response(metadata.dig('evidence', 'response')), response: build_evidence_response(evidence_data&.dig('response')),
source: build_evidence_source(metadata.dig('evidence', 'source')), source: build_evidence_source(evidence_data&.dig('source')),
supporting_messages: build_evidence_supporting_messages(metadata.dig('evidence', 'supporting_messages')) supporting_messages: build_evidence_supporting_messages(evidence_data&.dig('supporting_messages'))
} }
end end
......
...@@ -7,7 +7,7 @@ module Vulnerabilities ...@@ -7,7 +7,7 @@ module Vulnerabilities
belongs_to :finding, belongs_to :finding,
class_name: 'Vulnerabilities::Finding', class_name: 'Vulnerabilities::Finding',
inverse_of: :evidence, inverse_of: :finding_evidence,
foreign_key: 'vulnerability_occurrence_id', foreign_key: 'vulnerability_occurrence_id',
optional: false optional: false
......
...@@ -2,6 +2,55 @@ ...@@ -2,6 +2,55 @@
FactoryBot.define do FactoryBot.define do
factory :vulnerabilties_finding_evidence, class: 'Vulnerabilities::Finding::Evidence' do factory :vulnerabilties_finding_evidence, class: 'Vulnerabilities::Finding::Evidence' do
finding { association :vulnerabilities_finding }
summary { 'Evidence summary' } summary { 'Evidence summary' }
data do
{
summary: 'Credit card detected',
request: {
headers: [{ name: 'Accept', value: '*/*' }],
method: 'GET',
url: 'http://goat:8080/WebGoat/logout',
body: nil
},
response: {
headers: [{ name: 'Content-Length', value: '0' }],
reason_phrase: 'OK',
status_code: 200,
body: nil
},
source: {
id: 'assert:Response Body Analysis',
name: 'Response Body Analysis',
url: 'htpp://hostname/documentation'
},
supporting_messages: [
{
name: 'Origional',
request: {
headers: [{ name: 'Accept', value: '*/*' }],
method: 'GET',
url: 'http://goat:8080/WebGoat/logout',
body: ''
}
},
{
name: 'Recorded',
request: {
headers: [{ name: 'Accept', value: '*/*' }],
method: 'GET',
url: 'http://goat:8080/WebGoat/logout',
body: ''
},
response: {
headers: [{ name: 'Content-Length', value: '0' }],
reason_phrase: 'OK',
status_code: 200,
body: ''
}
}
]
}
end
end end
end end
...@@ -25,7 +25,7 @@ RSpec.describe Vulnerabilities::Finding do ...@@ -25,7 +25,7 @@ RSpec.describe Vulnerabilities::Finding do
it { is_expected.to have_many(:finding_remediations).class_name('Vulnerabilities::FindingRemediation').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(:vulnerability_flags).class_name('Vulnerabilities::Flag').with_foreign_key('vulnerability_occurrence_id') } it { is_expected.to have_many(:vulnerability_flags).class_name('Vulnerabilities::Flag').with_foreign_key('vulnerability_occurrence_id') }
it { is_expected.to have_many(:remediations).through(:finding_remediations) } it { is_expected.to have_many(:remediations).through(:finding_remediations) }
it { is_expected.to have_one(:evidence).class_name('Vulnerabilities::Finding::Evidence').with_foreign_key('vulnerability_occurrence_id') } it { is_expected.to have_one(:finding_evidence).class_name('Vulnerabilities::Finding::Evidence').with_foreign_key('vulnerability_occurrence_id') }
end end
describe 'validations' do describe 'validations' do
...@@ -775,79 +775,87 @@ RSpec.describe Vulnerabilities::Finding do ...@@ -775,79 +775,87 @@ RSpec.describe Vulnerabilities::Finding do
describe '#evidence' do describe '#evidence' do
subject { finding.evidence } subject { finding.evidence }
context 'has an evidence fields' do shared_examples 'evidence schema' do
let(:finding) { create(:vulnerabilities_finding) } it 'matches evidence schema' do
let(:evidence) { finding.metadata['evidence'] } example_evidence = evidence.with_indifferent_access
is_expected.to match a_hash_including(
summary: example_evidence['summary']
)
it do
is_expected.to match a_hash_including( is_expected.to match a_hash_including(
summary: evidence['summary'],
request: { request: {
headers: [ headers: [
{ {
name: evidence['request']['headers'][0]['name'], name: example_evidence['request']['headers'][0]['name'],
value: evidence['request']['headers'][0]['value'] value: example_evidence['request']['headers'][0]['value']
} }
], ],
url: evidence['request']['url'], url: example_evidence['request']['url'],
method: evidence['request']['method'], method: example_evidence['request']['method'],
body: evidence['request']['body'] body: example_evidence['request']['body']
}, }
)
is_expected.to match a_hash_including(
response: { response: {
headers: [ headers: [
{ {
name: evidence['response']['headers'][0]['name'], name: example_evidence['response']['headers'][0]['name'],
value: evidence['response']['headers'][0]['value'] value: example_evidence['response']['headers'][0]['value']
} }
], ],
reason_phrase: evidence['response']['reason_phrase'], reason_phrase: example_evidence['response']['reason_phrase'],
status_code: evidence['response']['status_code'], status_code: example_evidence['response']['status_code'],
body: evidence['request']['body'] body: example_evidence['request']['body']
}, },
source: { source: {
id: evidence.dig('source', 'id'), id: example_evidence.dig('source', 'id'),
name: evidence.dig('source', 'name'), name: example_evidence.dig('source', 'name'),
url: evidence.dig('source', 'url') url: example_evidence.dig('source', 'url')
}, }
)
is_expected.to match a_hash_including(
supporting_messages: [ supporting_messages: [
{ {
name: evidence.dig('supporting_messages')[0].dig('name'), name: example_evidence.dig('supporting_messages')[0].dig('name'),
request: { request: {
headers: [ headers: [
{ {
name: evidence.dig('supporting_messages')[0].dig('request', 'headers')[0].dig('name'), name: example_evidence.dig('supporting_messages')[0].dig('request', 'headers')[0].dig('name'),
value: evidence.dig('supporting_messages')[0].dig('request', 'headers')[0].dig('value') value: example_evidence.dig('supporting_messages')[0].dig('request', 'headers')[0].dig('value')
} }
], ],
url: evidence.dig('supporting_messages')[0].dig('request', 'url'), url: example_evidence.dig('supporting_messages')[0].dig('request', 'url'),
method: evidence.dig('supporting_messages')[0].dig('request', 'method'), method: example_evidence.dig('supporting_messages')[0].dig('request', 'method'),
body: evidence.dig('supporting_messages')[0].dig('request', 'body') body: example_evidence.dig('supporting_messages')[0].dig('request', 'body')
}, },
response: evidence.dig('supporting_messages')[0].dig('response') response: example_evidence.dig('supporting_messages')[0].dig('response')
}, },
{ {
name: evidence.dig('supporting_messages')[1].dig('name'), name: example_evidence.dig('supporting_messages')[1].dig('name'),
request: { request: {
headers: [ headers: [
{ {
name: evidence.dig('supporting_messages')[1].dig('request', 'headers')[0].dig('name'), name: example_evidence.dig('supporting_messages')[1].dig('request', 'headers')[0].dig('name'),
value: evidence.dig('supporting_messages')[1].dig('request', 'headers')[0].dig('value') value: example_evidence.dig('supporting_messages')[1].dig('request', 'headers')[0].dig('value')
} }
], ],
url: evidence.dig('supporting_messages')[1].dig('request', 'url'), url: example_evidence.dig('supporting_messages')[1].dig('request', 'url'),
method: evidence.dig('supporting_messages')[1].dig('request', 'method'), method: example_evidence.dig('supporting_messages')[1].dig('request', 'method'),
body: evidence.dig('supporting_messages')[1].dig('request', 'body') body: example_evidence.dig('supporting_messages')[1].dig('request', 'body')
}, },
response: { response: {
headers: [ headers: [
{ {
name: evidence.dig('supporting_messages')[1].dig('response', 'headers')[0].dig('name'), name: example_evidence.dig('supporting_messages')[1].dig('response', 'headers')[0].dig('name'),
value: evidence.dig('supporting_messages')[1].dig('response', 'headers')[0].dig('value') value: example_evidence.dig('supporting_messages')[1].dig('response', 'headers')[0].dig('value')
} }
], ],
reason_phrase: evidence.dig('supporting_messages')[1].dig('response', 'reason_phrase'), reason_phrase: example_evidence.dig('supporting_messages')[1].dig('response', 'reason_phrase'),
status_code: evidence.dig('supporting_messages')[1].dig('response', 'status_code'), status_code: example_evidence.dig('supporting_messages')[1].dig('response', 'status_code'),
body: evidence.dig('supporting_messages')[1].dig('response', 'body') body: example_evidence.dig('supporting_messages')[1].dig('response', 'body')
} }
} }
] ]
...@@ -855,6 +863,14 @@ RSpec.describe Vulnerabilities::Finding do ...@@ -855,6 +863,14 @@ RSpec.describe Vulnerabilities::Finding do
end end
end end
context 'without finding_evidence' do
context 'has an evidence fields' do
let(:finding) { create(:vulnerabilities_finding) }
let(:evidence) { finding.metadata['evidence'] }
include_examples 'evidence schema'
end
context 'has no evidence summary when evidence is present, summary is not' do context 'has no evidence summary when evidence is present, summary is not' do
let(:finding) { create(:vulnerabilities_finding, raw_metadata: { evidence: {} }) } let(:finding) { create(:vulnerabilities_finding, raw_metadata: { evidence: {} }) }
...@@ -869,6 +885,15 @@ RSpec.describe Vulnerabilities::Finding do ...@@ -869,6 +885,15 @@ RSpec.describe Vulnerabilities::Finding do
end end
end end
context 'with finding_evidence' do
let(:finding_evidence) { build(:vulnerabilties_finding_evidence) }
let(:finding) { finding_evidence.finding }
let(:evidence) { finding_evidence.data }
include_examples 'evidence schema'
end
end
describe '#message' do describe '#message' do
let(:finding) { build(:vulnerabilities_finding) } let(:finding) { build(:vulnerabilities_finding) }
let(:expected_message) { finding.metadata['message'] } let(:expected_message) { finding.metadata['message'] }
......
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