Below is a Ruby program that is supposed to verify a connection with my GitHub repos, private and public.
The ssh key is the correct one, and it has no passphrase. However, ssh is apparently not used, as shown near the end of this question.
require 'pathname'
require 'rugged'
base = ARGV[0] || '.'
base_fq = Pathname.new(base).realpath.to_s
repo = Rugged::Repository.new base_fq
puts repo.inspect
remote = repo.remotes['origin']
puts "remote.name=#{remote.name}, remote.url=#{remote.url}, remote.fetch_refspecs=#{remote.fetch_refspecs}"
credentials = Rugged::Credentials::SshKey.new(
username: 'git',
passphrase: nil,
privatekey: File.expand_path('~/.ssh/id_rsa'),
publickey: File.expand_path('~/.ssh/id_rsa.pub')
)
puts credentials.inspect
success = remote.check_connection(:fetch, credentials: credentials)
puts "remote.check_connection(:fetch, credentials: credentials) returned #{success}"
success = remote.fetch(credentials: credentials)
puts "remote.fetch(credentials: credentials) returned #{success}"
Output is:
#<Rugged::Repository:60 {path: "/mnt/c/work/ruby/update/.git/"}>
remote.name=origin, [email protected]:mslinn/update.git, remote.fetch_refspecs=["+refs/heads/*:refs/remotes/origin/*"]#<Rugged::Credentials::SshKey:0x00007fee350db648 @username="git", @publickey="/home/mslinn/.ssh/id_rsa.pub", @privatekey="/home/mslinn/.ssh/id_rsa", @passphrase=nil>
remote.check_connection(:fetch, credentials: credentials) returned false
lib/check_connection.rb:21:in `fetch': unsupported URL protocol (Rugged::NetworkError)
from lib/check_connection.rb:21:in `<main>'```
Why does check_connection always return false? Presumably that is also the reason the fetch raises an exception.
Connecting Via ssh
I can connect via ssh:
$ ssh github.com
Warning: No xauth data; using fake authentication data for X11 forwarding.
X11 forwarding request failed on channel 0
PTY allocation request failed on channel 0
Hi mslinn! You've successfully authenticated, but GitHub does not provide shell access.
Connection to github.com closed.
My ~/.ssh/config file contains:
Compression yes
ForwardX11 yes
ForwardX11Trusted yes
XAuthLocation /usr/bin/xauth
Host github.com
User git
PreferredAuthentications publickey
I discovered that libgit2 uses libssh2 for ssh support.
However, libssh2 does not read config settings from ~/.ssh/config, so libgit2 does not support that either.
libssh2 Limitation
I found this on the GitHub blog:
If you’re using libgit2 or another piece of code using libssh2, we recommend you use libssh2 1.9.0 or newer and an ECDSA key, since it does not yet support RSA with SHA-2. Similarly, the Go SSH client also doesn’t yet support RSA with SHA-2, so we recommend using an Ed25519 key there.
I am using an RSA with SHA-2 key, which might be the problem:
$ ssh-keygen -l -f ~/.ssh/id_rsa
1024 SHA256:Xdv1AE4QTd0NfrwOGVTamF/wxnvFufCtsOIoOXtX5Mw Administrator@CHLOE (RSA)
Missing libgit2 ssh Feature
Here is how to discover the features that libgit2 was built with:
$ irb
irb(main):001:0> require 'rugged'
=> true
irb(main):002:0> Rugged.libgit2_version
=> [1, 6, 3]
irb(main):003:0> Rugged.features
=> [:threads, :https]
The above output shows the library is up-to-date (version 1.6.3), but it was not built with :ssh, so that is definitely a problem. I'll have to build the library to include that feature.
$ gem install rugged -- --with-ssh
Building native extensions with: '--with-ssh'
This could take a while...
Successfully installed rugged-1.6.3
$ irb
irb(main):001:0> require 'rugged'
=> true
irb(main):002:0> Rugged.features
=> [:threads, :https, :ssh]
ssh Not Used
I configured the git ssh command to increase verbosity:
$ git config core.sshCommand "ssh -vi ~/.ssh/id_rsa"
Now when I type git pull, the expected ssh debug information is displayed. However, this does not affect the output of my test program.
Two possibilities:
Perhaps
libgit2(and hencerugged) does not use the systemssh? After digging around on the Interwebs I believe this is true.Perhaps
libgit2(and hencerugged) does not support thecore.sshCommandsetting?
ssh-agent
No agent is required for git, it is optional, and I was not using one:
$ ssh-add -L
Could not open a connection to your authentication agent.
I set up ssh-agent and tried again:
$ eval $(ssh-agent) > /dev/null
$ ssh-add
Identity added: /home/mslinn/.ssh/id_rsa (/home/mslinn/.ssh/id_rsa)
$ ssh-add -l
1024 SHA256:Xdv1AE4QTd0NfrwOGVTamF/wxnvFufCtsOIoOXtX5Mw
/home/mslinn/.ssh/id_rsa (RSA)
$ echo $SSH_AGENT_PID
2196
Then I changed the Ruby program to compute credentials using ssh-agent:
credentials = Rugged::Credentials::SshKeyFromAgent.new(username: 'git')
However, the Ruby program failed as before. Here is the output:
#<Rugged::Repository:60 {path: "/var/work/ruby/update/.git/"}>
remote.name=origin, [email protected]:mslinn/update.git, remote.fetch_refspecs=["+refs/heads/*:refs/remotes/origin/*"]
#<Rugged::Credentials::SshKeyFromAgent:0x00007fa290d169d0 @username="git">
remote.check_connection(:fetch, credentials: credentials) returned false
After clambering over hill and dale, the problem was that
libgit2as provided by theruggedgem does not includesshsupport. I showed how to do that above by using thegemcommand.Bundler can also be configured to build
libgit2withsshsupport:After typing the above, the next time you run
bundle installon a Ruby project that specifiesruggedas a dependency, if the resolved version ofruggedis not installed, it will be built withsshsupport.Once the above was done, the problem went away:
It is probably a good idea to add this to every
ruggedproject:For more information, see Working With Git Repos Using Ruby's Rugged Gem.