233 lines
7.1 KiB
Ruby
233 lines
7.1 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'spec_helper'
|
|
|
|
RSpec.describe Gitlab::BackgroundMigration::FixVulnerabilityOccurrencesWithHashesAsRawMetadata, schema: 20211209203821 do
|
|
let(:users) { table(:users) }
|
|
let(:namespaces) { table(:namespaces) }
|
|
let(:projects) { table(:projects) }
|
|
let(:scanners) { table(:vulnerability_scanners) }
|
|
let(:identifiers) { table(:vulnerability_identifiers) }
|
|
let(:findings) { table(:vulnerability_occurrences) }
|
|
|
|
let(:user) { users.create!(name: 'Test User', projects_limit: 10, username: 'test-user', email: '1') }
|
|
|
|
let(:namespace) do
|
|
namespaces.create!(
|
|
owner_id: user.id,
|
|
name: user.name,
|
|
path: user.username
|
|
)
|
|
end
|
|
|
|
let(:project) do
|
|
projects.create!(namespace_id: namespace.id, name: 'Test Project')
|
|
end
|
|
|
|
let(:scanner) do
|
|
scanners.create!(
|
|
project_id: project.id,
|
|
external_id: 'test-scanner',
|
|
name: 'Test Scanner',
|
|
vendor: 'GitLab'
|
|
)
|
|
end
|
|
|
|
let(:primary_identifier) do
|
|
identifiers.create!(
|
|
project_id: project.id,
|
|
external_type: 'cve',
|
|
name: 'CVE-2021-1234',
|
|
external_id: 'CVE-2021-1234',
|
|
fingerprint: '4c0fe491999f94701ee437588554ef56322ae276'
|
|
)
|
|
end
|
|
|
|
let(:finding) do
|
|
findings.create!(
|
|
raw_metadata: raw_metadata,
|
|
project_id: project.id,
|
|
scanner_id: scanner.id,
|
|
primary_identifier_id: primary_identifier.id,
|
|
uuid: '4deb090a-bedf-5ccc-aa9a-ac8055a1ea81',
|
|
project_fingerprint: '1caa750a6dad769a18ad6f40b413b3b6ab1c8d77',
|
|
location_fingerprint: '6d1f35f53b065238abfcadc01336ce65d112a2bd',
|
|
name: 'name',
|
|
report_type: 7,
|
|
severity: 0,
|
|
confidence: 0,
|
|
detection_method: 'gitlab_security_report',
|
|
metadata_version: 'cluster_image_scanning:1.0',
|
|
created_at: "2021-12-10 14:27:42 -0600",
|
|
updated_at: "2021-12-10 14:27:42 -0600"
|
|
)
|
|
end
|
|
|
|
subject(:perform) { described_class.new.perform(finding.id, finding.id) }
|
|
|
|
context 'with stringified hash as raw_metadata' do
|
|
let(:raw_metadata) do
|
|
'{:location=>{"image"=>"index.docker.io/library/nginx:latest", "kubernetes_resource"=>{"namespace"=>"production", "kind"=>"deployment", "name"=>"nginx", "container_name"=>"nginx", "agent_id"=>"2"}, "dependency"=>{"package"=>{"name"=>"libc"}, "version"=>"v1.2.3"}}}'
|
|
end
|
|
|
|
it 'converts stringified hash to JSON' do
|
|
expect { perform }.not_to raise_error
|
|
|
|
result = finding.reload.raw_metadata
|
|
metadata = Oj.load(result)
|
|
expect(metadata).to eq(
|
|
{
|
|
'location' => {
|
|
'image' => 'index.docker.io/library/nginx:latest',
|
|
'kubernetes_resource' => {
|
|
'namespace' => 'production',
|
|
'kind' => 'deployment',
|
|
'name' => 'nginx',
|
|
'container_name' => 'nginx',
|
|
'agent_id' => '2'
|
|
},
|
|
'dependency' => {
|
|
'package' => { 'name' => 'libc' },
|
|
'version' => 'v1.2.3'
|
|
}
|
|
}
|
|
}
|
|
)
|
|
end
|
|
end
|
|
|
|
context 'with valid raw_metadata' do
|
|
where(:raw_metadata) do
|
|
[
|
|
'{}',
|
|
'{"location":null}',
|
|
'{"location":{"image":"index.docker.io/library/nginx:latest","kubernetes_resource":{"namespace":"production","kind":"deployment","name":"nginx","container_name":"nginx","agent_id":"2"},"dependency":{"package":{"name":"libc"},"version":"v1.2.3"}}}'
|
|
]
|
|
end
|
|
|
|
with_them do
|
|
it 'does not change the raw_metadata' do
|
|
expect { perform }.not_to raise_error
|
|
|
|
result = finding.reload.raw_metadata
|
|
expect(result).to eq(raw_metadata)
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'when raw_metadata contains forbidden types' do
|
|
using RSpec::Parameterized::TableSyntax
|
|
|
|
where(:raw_metadata, :type) do
|
|
'def foo; "bar"; end' | :def
|
|
'`cat somefile`' | :xstr
|
|
'exec("cat /etc/passwd")' | :send
|
|
end
|
|
|
|
with_them do
|
|
it 'does not change the raw_metadata' do
|
|
expect(Gitlab::AppLogger).to receive(:error).with(message: "expected raw_metadata to be a hash", type: type)
|
|
|
|
expect { perform }.not_to raise_error
|
|
|
|
result = finding.reload.raw_metadata
|
|
expect(result).to eq(raw_metadata)
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'when forbidden types are nested inside a hash' do
|
|
using RSpec::Parameterized::TableSyntax
|
|
|
|
where(:raw_metadata, :type) do
|
|
'{:location=>Env.fetch("SOME_VAR")}' | :send
|
|
'{:location=>{:image=>Env.fetch("SOME_VAR")}}' | :send
|
|
# rubocop:disable Lint/InterpolationCheck
|
|
'{"key"=>"value: #{send}"}' | :dstr
|
|
# rubocop:enable Lint/InterpolationCheck
|
|
end
|
|
|
|
with_them do
|
|
it 'does not change the raw_metadata' do
|
|
expect(Gitlab::AppLogger).to receive(:error).with(
|
|
message: "error parsing raw_metadata",
|
|
error: "value of a pair was an unexpected type",
|
|
type: type
|
|
)
|
|
|
|
expect { perform }.not_to raise_error
|
|
|
|
result = finding.reload.raw_metadata
|
|
expect(result).to eq(raw_metadata)
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'when key is an unexpected type' do
|
|
let(:raw_metadata) { "{nil=>nil}" }
|
|
|
|
it 'logs error' do
|
|
expect(Gitlab::AppLogger).to receive(:error).with(
|
|
message: "error parsing raw_metadata",
|
|
error: "expected key to be either symbol, string, or integer",
|
|
type: :nil
|
|
)
|
|
|
|
expect { perform }.not_to raise_error
|
|
end
|
|
end
|
|
|
|
context 'when raw_metadata cannot be parsed' do
|
|
let(:raw_metadata) { "{" }
|
|
|
|
it 'logs error' do
|
|
expect(Gitlab::AppLogger).to receive(:error).with(message: "error parsing raw_metadata", error: "unexpected token $end")
|
|
|
|
expect { perform }.not_to raise_error
|
|
end
|
|
end
|
|
|
|
describe '#hash_from_s' do
|
|
subject { described_class.new.hash_from_s(input) }
|
|
|
|
context 'with valid input' do
|
|
let(:input) { '{:location=>{"image"=>"index.docker.io/library/nginx:latest", "kubernetes_resource"=>{"namespace"=>"production", "kind"=>"deployment", "name"=>"nginx", "container_name"=>"nginx", "agent_id"=>2}, "dependency"=>{"package"=>{"name"=>"libc"}, "version"=>"v1.2.3"}}}' }
|
|
|
|
it 'converts string to a hash' do
|
|
expect(subject).to eq({
|
|
location: {
|
|
'image' => 'index.docker.io/library/nginx:latest',
|
|
'kubernetes_resource' => {
|
|
'namespace' => 'production',
|
|
'kind' => 'deployment',
|
|
'name' => 'nginx',
|
|
'container_name' => 'nginx',
|
|
'agent_id' => 2
|
|
},
|
|
'dependency' => {
|
|
'package' => { 'name' => 'libc' },
|
|
'version' => 'v1.2.3'
|
|
}
|
|
}
|
|
})
|
|
end
|
|
end
|
|
|
|
using RSpec::Parameterized::TableSyntax
|
|
|
|
where(:input, :expected) do
|
|
'{}' | {}
|
|
'{"bool"=>true}' | { 'bool' => true }
|
|
'{"bool"=>false}' | { 'bool' => false }
|
|
'{"nil"=>nil}' | { 'nil' => nil }
|
|
'{"array"=>[1, "foo", nil]}' | { 'array' => [1, "foo", nil] }
|
|
'{foo: :bar}' | { foo: :bar }
|
|
'{foo: {bar: "bin"}}' | { foo: { bar: "bin" } }
|
|
end
|
|
|
|
with_them do
|
|
specify { expect(subject).to eq(expected) }
|
|
end
|
|
end
|
|
end
|