Introduction

In this installment of the Redmine tutorial series, I will instruct users on how to add SSH authentication to their private mercurial repos created earlier in the series.

This will allow users to perform mercurial (hg) operations e.g. push, pull, clone , on their repositories without having to input their credentials each time (as is the default with HTTP(S)).

SSH makes use of both a public and private keypair which we will start by creating on our local machine.

On your local client:

On your local machine, create an RSA keypair

ssh-keygen -t rsa -b 4096 -C "your_email@example.com"

Start the local SSH agent in the background

eval "$(ssh-agent -s)"

Add your private key to the SSH agent

ssh-add -K ~/.ssh/id_rsa

Copy your public key to the server

scp -v ~/.ssh/id_rsa.pub [username]@[your_domain]:~

On the Server:

Install Mercurial server

sudo apt-get install mercurial-server

Move the newly copied key from your client to the mercurial-server key directory:

sudo mv -v id_rsa.pub /etc/mercurial-server/keys/root/<yourRedmineUserName>

Test if the installation was successful:

Load the key into mercurial server by running the refresh-auth program:

sudo -u hg /usr/share/mercurial-server/refresh-auth

Clone the hgadmin test repo locally:

hg clone ssh://hg@[your_domain]/hgadmin

You should get:

$hg clone ssh://hg@[your_domain]/hgadmin
The authenticity of host 'your_domain (XX.XX.X.XX)' can't be established.
ECDSA key fingerprint is SHA256:QqLOjvSBFAGDo6v5PeG1evT9kJrT9Y8EsLqFEa7H2BE.
Are you sure you want to continue connecting (yes/no)? yes
remote: Warning: Permanently added '[your_domain]' (ECDSA) to the list of known hosts.
destination directory: hgadmin
no changes found
updating to branch default
0 files updated, 0 files merged, 0 files removed, 0 files unresolved

Edit the mercurial server config:

sudo vi /var/lib/mercurial-server/.mercurial-server
Modify repos = ~/repos to:

repos = /var/hg/repos

Modify the hg account permissions:

Check the groups that hg user belongs to:

id hg

Add the hg user to the www-data group:

sudo usermod -G www-data hg

Give the group write permissions on the repository:

sudo chmod -R g+w /var/hg/repos/test

Add the changegroup hook:

sudo vi /etc/mercurial-server/remote-hgrc.d/access.rc

Add under [hooks], add the following:

changegroup = /var/hg/changegroup-hook

On your local client:

Clone the repo locally, edit a file, commit and push changes:

hg clone ssh://hg@[your_domain]/test

You should see:

$hg clone ssh://hg@[your_domain]/test
destination directory: test
requesting all changes
remote: error: outgoing.aaaaa_servelog hook raised an exception: 'localrepository' object has no attribute 'join'
remote: (run with --traceback for stack trace)
adding changesets
adding manifests
adding file changes
added 3 changesets with 3 changes to 1 files
new changesets 99c57e1db0ac:54e179c4267b
updating to branch default
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
<edit file>
hg push

You should see:

$hg push
pushing to ssh://hg@[your_domain]/test
searching for changes
remote: adding changesets
remote: adding manifests
remote: adding file changes
remote: added 1 changesets with 1 changes to 1 files
remote: error: changegroup.aaaaa_servelog hook raised an exception: 'localrepository' object has no attribute 'join'
remote: (run with --traceback for stack trace)

In case you get the following errors when doing a push or a clone:

remote: error: changegroup.aaaaa_servelog hook raised an exception: 'localrepository' object has no attribute 'join'

Or:

remote: error: outgoing.aaaaa_servelog hook raised an exception: 'localrepository' object has no attribute 'join'
remote: (run with --traceback for stack trace)

The solution is to comment out the default logging hooks in the logging.rc file:

sudo vi /etc/mercurial-server/remote-hgrc.d/logging.rc

Change the file to the following:

[hooks]
# changegroup.aaaaa_servelog = python:mercurialserver.servelog.hook
# outgoing.aaaaa_servelog = python:mercurialserver.servelog.hook