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