From 6c3b6c75beaf3808649f9471ff4ac98f63b8b729 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tina=20M=C3=BCller?= Date: Tue, 28 Jan 2025 21:54:12 +0100 Subject: [PATCH] Prevent git from prompting for credentials There can be situations where git needs credentials and prompts the user, * Trying to push to via http * Trying to push via ssh but without having a key, or a key with a passphrase * Trying to fetch from a private repo via http or ssh This does not make sense in automated code and results in a hanging process waitign for input. We can prevent a prompt by setting the following two variables: https://git-scm.com/docs/git#Documentation/git.txt-codeGITASKPASScode GIT_ASKPASS If this environment variable is set, then Git commands which need to acquire passwords or passphrases (e.g. for HTTP or IMAP authentication) will call this program with a suitable prompt as command-line argument and read the password from its STDOUT. See also the core.askPass option in git-config[1]. https://git-scm.com/docs/git#Documentation/git.txt-codeGITTERMINALPROMPTcode GIT_TERMINAL_PROMPT If this Boolean environment variable is set to false, git will not prompt on the terminal (e.g., when asking for HTTP authentication). This way we will immediately get an error message. Issue: https://progress.opensuse.org/issues/174592 In this case the error presented to the user is: "Unable to push Git commit (/path/to/needles): remote: Support for password authentication was removed on August 13, 2021. remote: Please see https://docs.github.com/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication. fatal: Authentication failed for 'https://github.com/perlpunk/os-autoinst-needles-openQA/'" That can be improved in a followup by adding a link to our documentation. --- lib/OpenQA/Git.pm | 4 ++-- t/14-grutasks-git.t | 23 ++++++++++++----------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/lib/OpenQA/Git.pm b/lib/OpenQA/Git.pm index c5d8664a0d1..ab2809db075 100644 --- a/lib/OpenQA/Git.pm +++ b/lib/OpenQA/Git.pm @@ -32,7 +32,7 @@ sub _run_cmd ($self, $args, $options = {}) { my $include_git_path = $options->{include_git_path} // 1; my $batchmode = $options->{batchmode} // 0; my @cmd; - push @cmd, 'env', 'GIT_SSH_COMMAND=ssh -oBatchMode=yes' if $batchmode; + push @cmd, 'env', 'GIT_SSH_COMMAND=ssh -oBatchMode=yes', 'GIT_ASKPASS=echo', 'GIT_TERMINAL_PROMPT=false' if $batchmode; push @cmd, $self->_prepare_git_command($include_git_path), @$args; my $result = run_cmd_with_log_return_error(\@cmd); @@ -97,7 +97,7 @@ sub commit ($self, $args = undef) { # push changes if (($self->config->{do_push} || '') eq 'yes') { - $res = $self->_run_cmd(['push']); + $res = $self->_run_cmd(['push'], {batchmode => 1}); return $self->_format_git_error($res, 'Unable to push Git commit') unless $res->{status}; } diff --git a/t/14-grutasks-git.t b/t/14-grutasks-git.t index 63c989c4dc1..1b71510d656 100644 --- a/t/14-grutasks-git.t +++ b/t/14-grutasks-git.t @@ -60,7 +60,7 @@ subtest 'git clone' => sub { run_cmd_with_log_return_error => sub ($cmd) { push @mocked_git_calls, join(' ', map { tr/ // ? "'$_'" : $_ } @$cmd) =~ s/\Q$git_clones//r; my $stdout = ''; - splice @$cmd, 0, 2 if $cmd->[0] eq 'env'; + splice @$cmd, 0, 4 if $cmd->[0] eq 'env'; my $path = ''; (undef, $path) = splice @$cmd, 1, 2 if $cmd->[1] eq '-C'; my $action = $cmd->[1]; @@ -109,6 +109,7 @@ subtest 'git clone' => sub { }); my @gru_args = ($t->app, 'git_clone', $clone_dirs, {priority => 10}); my $res = run_gru_job(@gru_args); + is $res->{result}, 'Job successfully executed', 'minion job result indicates success'; #<<< no perltidy my $expected_calls = [ @@ -121,20 +122,20 @@ subtest 'git clone' => sub { ['rev-parse' => 'git -C /sha2 rev-parse --verify -q def'], ['check dirty' => 'git -C /sha2 diff-index HEAD --exit-code'], ['current branch' => 'git -C /sha2 branch --show-current'], - ['fetch branch' => "env 'GIT_SSH_COMMAND=ssh -oBatchMode=yes' git -C /sha2 fetch origin def"], + ['fetch branch' => "env 'GIT_SSH_COMMAND=ssh -oBatchMode=yes' GIT_ASKPASS=echo GIT_TERMINAL_PROMPT=false git -C /sha2 fetch origin def"], # /branch ['get-url' => 'git -C /branch/ remote get-url origin'], ['check dirty' => 'git -C /branch/ diff-index HEAD --exit-code'], ['current branch' => 'git -C /branch/ branch --show-current'], - ['fetch branch' => "env 'GIT_SSH_COMMAND=ssh -oBatchMode=yes' git -C /branch/ fetch origin foobranch"], + ['fetch branch' => "env 'GIT_SSH_COMMAND=ssh -oBatchMode=yes' GIT_ASKPASS=echo GIT_TERMINAL_PROMPT=false git -C /branch/ fetch origin foobranch"], # /default/ ['get-url' => 'git -C /default/ remote get-url origin'], ['check dirty' => 'git -C /default/ diff-index HEAD --exit-code'], - ['default remote' => "env 'GIT_SSH_COMMAND=ssh -oBatchMode=yes' git ls-remote --symref http://localhost/foo.git HEAD"], + ['default remote' => "env 'GIT_SSH_COMMAND=ssh -oBatchMode=yes' GIT_ASKPASS=echo GIT_TERMINAL_PROMPT=false git ls-remote --symref http://localhost/foo.git HEAD"], ['current branch' => 'git -C /default/ branch --show-current'], - ['fetch default' => "env 'GIT_SSH_COMMAND=ssh -oBatchMode=yes' git -C /default/ fetch origin master"], + ['fetch default' => "env 'GIT_SSH_COMMAND=ssh -oBatchMode=yes' GIT_ASKPASS=echo GIT_TERMINAL_PROMPT=false git -C /default/ fetch origin master"], ['reset' => 'git -C /default/ reset --hard origin/master'], # /sha-branchname @@ -142,10 +143,10 @@ subtest 'git clone' => sub { ['rev-parse' => 'git -C /sha-branchname rev-parse --verify -q a123'], ['check dirty' => 'git -C /sha-branchname diff-index HEAD --exit-code'], ['current branch' => 'git -C /sha-branchname branch --show-current'], - ['fetch branch' => "env 'GIT_SSH_COMMAND=ssh -oBatchMode=yes' git -C /sha-branchname fetch origin a123"], + ['fetch branch' => "env 'GIT_SSH_COMMAND=ssh -oBatchMode=yes' GIT_ASKPASS=echo GIT_TERMINAL_PROMPT=false git -C /sha-branchname fetch origin a123"], # /this_directory_does_not_exist/ - ['clone' => "env 'GIT_SSH_COMMAND=ssh -oBatchMode=yes' git clone http://localhost/bar.git /this_directory_does_not_exist/"], + ['clone' => "env 'GIT_SSH_COMMAND=ssh -oBatchMode=yes' GIT_ASKPASS=echo GIT_TERMINAL_PROMPT=false git clone http://localhost/bar.git /this_directory_does_not_exist/"], ]; #>>> no perltidy for my $i (0 .. $#$expected_calls) { @@ -222,17 +223,17 @@ subtest 'git clone' => sub { # /opensuse ['get-url' => 'git -C /opensuse remote get-url origin'], ['check dirty' => 'git -C /opensuse diff-index HEAD --exit-code'], - ['default remote' => "env 'GIT_SSH_COMMAND=ssh -oBatchMode=yes' git ls-remote --symref http://osado HEAD"], + ['default remote' => "env 'GIT_SSH_COMMAND=ssh -oBatchMode=yes' GIT_ASKPASS=echo GIT_TERMINAL_PROMPT=false git ls-remote --symref http://osado HEAD"], ['current branch' => 'git -C /opensuse branch --show-current'], - ['fetch default ' => "env 'GIT_SSH_COMMAND=ssh -oBatchMode=yes' git -C /opensuse fetch origin master"], + ['fetch default ' => "env 'GIT_SSH_COMMAND=ssh -oBatchMode=yes' GIT_ASKPASS=echo GIT_TERMINAL_PROMPT=false git -C /opensuse fetch origin master"], ['reset' => 'git -C /opensuse reset --hard origin/master'], # /opensuse/needles ['get-url' => 'git -C /opensuse/needles remote get-url origin'], ['check dirty' => 'git -C /opensuse/needles diff-index HEAD --exit-code'], - ['default remote' => "env 'GIT_SSH_COMMAND=ssh -oBatchMode=yes' git ls-remote --symref http://osado HEAD"], + ['default remote' => "env 'GIT_SSH_COMMAND=ssh -oBatchMode=yes' GIT_ASKPASS=echo GIT_TERMINAL_PROMPT=false git ls-remote --symref http://osado HEAD"], ['current branch' => 'git -C /opensuse/needles branch --show-current'], - ['fetch branch' => "env 'GIT_SSH_COMMAND=ssh -oBatchMode=yes' git -C /opensuse/needles fetch origin master"], + ['fetch branch' => "env 'GIT_SSH_COMMAND=ssh -oBatchMode=yes' GIT_ASKPASS=echo GIT_TERMINAL_PROMPT=false git -C /opensuse/needles fetch origin master"], ['reset' => 'git -C /opensuse/needles reset --hard origin/master'], ]; #>>> no perltidy