gitlab-org--gitlab-foss/spec/lib/gitlab/background_migration/fix_vulnerability_occurrenc...

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