Skip to content
Snippets Groups Projects
Commit 27cfefdb authored by Darby Frey's avatar Darby Frey Committed by drew stachon
Browse files

Adding Secure Files integrity check

The integrity of uploaded Secure Files can now be verified via a rake task.

Changelog: changed
MR:
parent f3efa915
No related branches found
No related tags found
1 merge request!122504Adding Secure Files integrity check
......@@ -69,6 +69,10 @@ def update_metadata!
end
end
def local?
file_store == ObjectStorage::Store::LOCAL
end
private
def assign_checksum
......
# frozen_string_literal: true
module Gitlab
module Verify
class CiSecureFiles < BatchVerifier
def name
'CI Secure Files'
end
def describe(object)
"SecureFile: #{object.id}"
end
private
# rubocop: disable CodeReuse/ActiveRecord
def all_relation
::Ci::SecureFile.all
end
# rubocop: enable CodeReuse/ActiveRecord
def local?(secure_file)
secure_file.local?
end
def expected_checksum(secure_file)
secure_file.checksum
end
def actual_checksum(secure_file)
Digest::SHA256.hexdigest(secure_file.file.read)
end
def remote_object_exists?(secure_file)
secure_file.file.file.exists?
end
end
end
end
# frozen_string_literal: true
namespace :gitlab do
namespace :ci_secure_files do
desc 'GitLab | CI Secure Files | Check integrity of uploaded Secure Files'
task check: :environment do
Gitlab::Verify::RakeTask.run!(Gitlab::Verify::CiSecureFiles)
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Verify::CiSecureFiles, factory_default: :keep, feature_category: :mobile_devops do
include GitlabVerifyHelpers
it_behaves_like 'Gitlab::Verify::BatchVerifier subclass' do
let_it_be(:objects) { create_list(:ci_secure_file, 3) }
end
describe '#run_batches' do
let_it_be(:project) { create(:project) }
let(:failures) { collect_failures }
let(:failure) { failures[secure_file] }
let!(:secure_file) { create(:ci_secure_file, project: project) }
it 'passes secure_files with the correct file' do
expect(failures).to eq({})
end
it 'fails secure_files with a missing file' do
FileUtils.rm_f(secure_file.file.path)
expect(failures.keys).to contain_exactly(secure_file)
expect(failure).to include('No such file or directory')
expect(failure).to include(secure_file.file.path)
end
it 'fails secure_files with a mismatched checksum' do
secure_file.update!(checksum: 'something incorrect')
expect(failures.keys).to contain_exactly(secure_file)
expect(failure).to include('Checksum mismatch')
end
context 'with remote files' do
let(:file) { CarrierWaveStringFile.new }
before do
stub_ci_secure_file_object_storage
secure_file.update!(file_store: ObjectStorage::Store::REMOTE)
end
describe 'returned hash object' do
it 'passes secure_files in object storage that exist' do
expect(CarrierWave::Storage::Fog::File).to receive(:new).and_return(file)
expect(file).to receive(:exists?).and_return(true)
expect(failures).to eq({})
end
it 'fails secure_files in object storage that do not exist' do
expect(CarrierWave::Storage::Fog::File).to receive(:new).and_return(file)
expect(file).to receive(:exists?).and_return(false)
expect(failures.keys).to contain_exactly(secure_file)
expect(failure).to include('Remote object does not exist')
end
end
end
end
end
......@@ -2,13 +2,14 @@
require 'spec_helper'
RSpec.describe Ci::SecureFile do
RSpec.describe Ci::SecureFile, factory_default: :keep, feature_category: :mobile_devops do
let_it_be(:project) { create_default(:project).freeze }
let(:sample_file) { fixture_file('ci_secure_files/upload-keystore.jks') }
before do
stub_ci_secure_file_object_storage
end
let(:sample_file) { fixture_file('ci_secure_files/upload-keystore.jks') }
subject { create(:ci_secure_file, file: CarrierWaveStringFile.new(sample_file)) }
it { is_expected.to be_a FileStoreMounter }
......@@ -60,10 +61,9 @@
describe 'ordered scope' do
it 'returns the newest item first' do
project = create(:project)
file1 = create(:ci_secure_file, created_at: 1.week.ago, project: project)
file2 = create(:ci_secure_file, created_at: 2.days.ago, project: project)
file3 = create(:ci_secure_file, created_at: 1.day.ago, project: project)
file1 = create(:ci_secure_file, created_at: 1.week.ago)
file2 = create(:ci_secure_file, created_at: 2.days.ago)
file3 = create(:ci_secure_file, created_at: 1.day.ago)
files = project.secure_files.order_by_created_at
......@@ -199,4 +199,17 @@
corrupt_file.update_metadata!
end
end
describe '#local?' do
it 'returns true when using local storage' do
secure_file = create(:ci_secure_file)
secure_file.update!(file_store: ObjectStorage::Store::LOCAL)
expect(secure_file.local?).to be true
end
it 'returns false when using object storage' do
secure_file = create(:ci_secure_file, file_store: ObjectStorage::Store::REMOTE)
expect(secure_file.local?).to be false
end
end
end
# frozen_string_literal: true
require 'rake_helper'
RSpec.describe 'gitlab:ci_secure_files', factory_default: :keep, feature_category: :mobile_devops do
describe 'check' do
let_it_be(:project) { create_default(:project).freeze }
let!(:secure_file) { create(:ci_secure_file) }
before do
Rake.application.rake_require('tasks/gitlab/ci_secure_files/check')
stub_env('VERBOSE' => 'true')
end
it 'outputs the integrity check for each batch' do
expect { run_rake_task('gitlab:ci_secure_files:check') }.to output(/Failures: 0/).to_stdout
end
it 'errors out about missing files on the file system' do
FileUtils.rm_f(secure_file.file.path)
expect do
run_rake_task('gitlab:ci_secure_files:check')
end.to output(/No such file.*#{Regexp.quote(secure_file.file.path)}/).to_stdout
end
it 'errors out about invalid checksum' do
secure_file.update_column(:checksum, 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855')
expect { run_rake_task('gitlab:ci_secure_files:check') }.to output(/Checksum mismatch/).to_stdout
end
end
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment