Making Mercurial use the Mac OS X Keychain

I’ve taken the plunge and am in the middle of switching from Subversion to Mercurial for revision control. Subversion has served me relatively faithfully for many years (I’ve even championed/led the adoption of subversion at two companies I’ve worked for in the past) but some of the warts and shortcomings were beginning to annoy me (. directories everywhere for example). Dave Dribin’s series of posts about the Mercurial DVCS software piqued my interest and I was soon switching repositories to hg.

One feature that added recently that hg lacked was the ability to store repository passwords in the Mac OS X keychain. In fact mercurial lacks the ability to store a repository password anywhere other than in the url used to access the repository (i.e. http://user:password@example.com/path). I think this is a bit of security flaw. The password is stored as plain text within the repository config file (‘.hg/hgrc’) file.

Fortunately Mercurial provides a simple interface for extension modules. After a little bit of hacking I was able to write an hg extension that stores and retrieves the password from the keychain. I’ve put the code online for anyone to use. hgkeychain:

And yes the source code is currently hosted in a Subversion repository :-) I did mention I’m in the middle of transitioning to Mercurial didn’t I?


Update

I’ve update the project for Mercurial 1.1 – it should now work on 1.1 and also 1.0 (and lower). I’ve also decided to move the code to bitbucket instead: https://www.bitbucket.org/schwa/hgkeychain/

This entry was posted in Default and tagged , , , , . Bookmark the permalink.
  • Thank you. I find it extremely useful.
  • Andreas
    Three things: www.bitbucket.org causes a certificate problem because of the "www" subdomain.

    Pure python keychain access: http://muffinresearch.co.uk/archives/2008/02/05... has a module for keychain access, without a .so required.Maybe this is interesting for you.

    Python conventions: Your code looks quite Ruby-like, you can monkey-patch (if you must) in a small scale without that __metaclass__ voodoo, by simply defining a method outside the class and assigning it:

    >>> class Foo(object):
    ... def bar(self):
    ... print "FooBar"
    ...
    >>> _baseFooBar = Foo.bar
    >>> def newBar(self):
    ... print "NewBar"
    ... _baseFooBar(self)
    ...
    >>> Foo.bar = newBar
    >>> Foo().bar()
    NewBar
    FooBar
  • @TeemuAP, yeah that might be interesting. The guys at turbogears do the same for their built-in server. I think they do it just by spawning the "dns-sd" tool. That should be relatively easy I'd imagine. Of course that would be Mac OS X only (again).
  • TeemuAP
    One thing I toyed around with: adding bonjour to 'hg serve'. That way guys around the table can find and access each other's repos without bothering with IPs/ports.

    Not knowing python I did not end up with anything publishable, just a ruby wrapper.
  • Giorgos, yeah I would love it to be part of the distribution however:

    1 It disables Mercurial's demandimport module. I couldn't get demandimport to work with my imports. And after a quick google I found it easier to disable the module than to fix things. Hopefully an hg expert can help me with this.

    2 it uses a Mac OS specific compiled C module.

    3 It monkey patches mercurial to override the password manager. I had to do this because I couldn't see how to access the password manager legitimately.

    I don't think this extension is suitable to be included with mercurial. But I will look into the idea of creating a patch that will provide this functionality in a less hacky manner.
  • keramida
    This seems like an extension that would be very useful to have in the main Mercurial distribution. Can we hope to lure you into submitting it to `mercurial-devel (at) selenic.com' as a patch?

    Cheers,
    Giorgos
blog comments powered by Disqus