spec/gitlab/qa/support/shell_command_spec.rb (74 lines of code) (raw):
# frozen_string_literal: true
describe Gitlab::QA::Support::ShellCommand do
describe 'execute!' do
context 'when masking secrets' do
let(:wait_thread) { instance_double(Thread) }
let(:errored_wait) { instance_double(Process::Status, exited?: true, exitstatus: 1) }
let(:non_errored_wait) { instance_double(Process::Status, exited?: true, exitstatus: 0) }
let(:stdin) { StringIO.new }
let(:stdout) { [+'logged in as ***** with password *****'] }
let(:logger) { Gitlab::QA::Runtime::Logger.logger }
let(:command) { +'login -u user -p secret' }
before do
Rainbow.enabled = false
allow(Open3).to receive(:popen2e).and_yield(stdin, stdout, wait_thread)
allow(Gitlab::QA::Runtime::Logger).to receive(:logger).and_return(logger)
end
subject(:shell_command) { described_class.new(command, mask_secrets: %w[secret user]) }
it 'masks secrets when logging the command itself' do
expect(logger).to receive(:info).with('Shell command: `login -u ***** -p *****`')
expect(wait_thread).to receive(:value).twice.and_return(non_errored_wait)
shell_command.execute!
end
it 'masks command secrets on CommandError' do
expect(wait_thread).to receive(:value).twice.and_return(errored_wait)
expect { shell_command.execute! }
.to raise_error(Gitlab::QA::Support::ShellCommand::StatusError, /Command `login -u \*{5} -p \*{5}` failed/)
end
it 'masks secrets when yielding output' do
expect(wait_thread).to receive(:value).twice.and_return(non_errored_wait)
shell_command.execute! do |output|
expect(output).not_to be_nil
expect(output).to eql('logged in as ***** with password *****')
end
end
it 'masks secrets in debug logs' do
expect(logger).to receive(:debug).with(/Shell command output:\nlogged in as \*{5} with password \*{5}/)
expect(wait_thread).to receive(:value).twice.and_return(non_errored_wait)
shell_command.execute!
end
it 'masks secrets in error logs' do
expect(logger).to receive(:error).with(/Shell command output:\nlogged in as \*{5} with password \*{5}/)
expect(wait_thread).to receive(:value).twice.and_return(errored_wait)
expect { shell_command.execute! }.to raise_error(Gitlab::QA::Support::ShellCommand::StatusError)
end
context 'when there is no secret' do
let(:command) { +'docker pull ruby:3' }
it 'returns the original string' do
expect(wait_thread).to receive(:value).twice.and_return(errored_wait)
expect { shell_command.execute! }
.to raise_error(Gitlab::QA::Support::ShellCommand::StatusError, /Command `docker pull ruby:3` failed/)
end
context 'with any other docker command other than attach' do
let(:command) { 'docker exec' }
it 'doesnt log' do
expect(wait_thread).to receive(:value).twice.and_return(errored_wait)
expect(logger).to receive(:error).with(/Shell command output:\nlogged in as \*{5} with password \*{5}/)
expect { shell_command.execute! }
.to raise_error(Gitlab::QA::Support::ShellCommand::StatusError, /Command `docker exec` failed/)
end
end
context 'for sig docker command' do # rubocop:disable RSpec/ContextWording
let(:command) { 'docker attach --sig-proxy=true' }
it 'does log' do
expect(wait_thread).to receive(:value).twice.and_return(errored_wait)
expect(logger).not_to receive(:error).with(/Shell command output:\nlogged in as \*{5} with password \*{5}/)
expect { shell_command.execute! }
.to raise_error(Gitlab::QA::Support::ShellCommand::StatusError,
/Command `docker attach --sig-proxy=true` failed/
)
end
end
end
end
end
end