Invalid credentials result in infinite loop
credentials = Rugged::Credentials::UserPassword.new({ username: 'user', password: 'abcd' })
repository = Rugged::Repository.clone_at('https://github.com/libgit2/private_repository',
'repository_clone/',
{ credentials: credentials })
results in an infinite loop.
According to https://github.com/libgit2/libgit2/issues/3358 and https://libgit2.github.com/libgit2/#HEAD/group/callback/git_cred_acquire_cb
git_cred_acquire_cb() is supposed to return GIT_EAUTH in case of invalid credentials, otherwise the callback will be called indefinitely.
Since username and password are static in this example, the callback returns GIT_OK (https://github.com/libgit2/rugged/blob/884f3672460c50a5cabfbcbe6b760e7070076a18/ext/rugged/rugged_remote.c#L155) and we're caught in the callback loop.
~~fixed with #596~~
@cschlack I think rugged uses the callback paradigm for credentials, so that you can hook it into a UI and keep asking the user for userid/password in case he enters an invalid one. From a UI perspective if the user hits cancel after several attempts it can raise its own error which rugged will propagate back to you.
I have a small script that I used with callbacks that sets the password once via a callback and on the next call it raises an exception. This sample uses a global variable but you could use an instance variable and achieve the same thing.
require 'rugged'
def self_signed(valid, host)
true
end
$credentials_set = false
def credentials(url, username, allowed_types)
raise "Invalid credentials" if $credentials_set
$credentials_set = true
Rugged::Credentials::UserPassword.new(:username => "root", :password => "secret")
end
options = {:remote => 'origin',
:credentials => method(:credentials),
:certificate_check => method(:self_signed)}
begin
Rugged::Repository.clone_at("https://a.b.c", "/tmp/dir", options)
rescue Rugged => e
puts e.message
end