Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
191 lines (148 sloc) 10.9 KB


Golem provides an easy way to host and manage access to git repositories on a server under a single user.

Gem and library name

The library name is Golem, but the gem is called gitgolem. After installing you could require either 'golem' or 'gitgolem'.

How it works

Golem's main goals are:

  • host git repositories under a single user,
  • manage access to repositories on a per-user basis,
  • store users and keys in a database,
  • to be simple as possible, but still extendable.

Golem is not designed to handle complex access rules, although it may be extended to achieve that. If you need more refined rules, like per-branch or per-path control you should check out { gitolite}, which has far superior features in this regard.

The git flow that golem supports is:

  • you have a specific shell user that "hosts" golem,
  • golem places your users ssh keys in this (shell) user's home directory (~/.ssh/authorized_keys),
  • your users use a git remote like golem_host_user@your_server:repository.git,
  • when a user git pushes/pulls, his git connects via ssh, sshd invokes golem's authorization command (via the authorized_keys file),
  • golem authorizes the user for the given repository and invokes git-shell if access granted.


Golem supports the following configuration variables:

  • db: the database to use, currently postgres ('postgres://...') and static ('static') supported,
  • user_home: the directory where the .ssh/authorized_keys file should be written, defaults to HOME environment variable,
  • repository_dir: path to the git repositories, may be relative to user_home,
  • cfg_path: path to config file, if not set searched for as (in this order):
    • GOLEM_CONFIG environment variable (if set),
    • 'golem.conf.rb' relative to GOLEM_BASE environment variable (if set),
    • /usr/local/etc/golem/golem.conf.rb,
    • /usr/local/etc/golem.conf.rb,
    • /etc/golem/golem.conf.rb,
    • /etc/golem.conf.rb,
    • ~/golem.conf.rb,
    • if found it is required (e.g. loaded), otherwise set to base_dir + "/golem.conf.rb" after configuration,
  • base_dir: convenience feature, may be used to store installation, if not explicitly set defaults to:
    • GOLEM_BASE environment variable (if set),
    • basedir of cfg_path if file exists,
    • basedir of the library itself (e.g. the gem path),
  • bin_dir: where the executable is installed, defaults to base_dir + "/bin",
  • hooks_dir: where the hooks are installed, defaults to base_dir + "/hooks",
  • keys_file_use_command: controls how to use .ssh/authorized_keys (environment="" or command=""), see {file:README#keys_file authorized_keys},
  • keys_file_ssh_opts: ssh options to place in .ssh/authorized_keys, see {file:README#keys_file authorized_keys}.

Git and .ssh/authorized_keys

Git supports SSH as the transport protocol for pulling and pushing, and assumes SSH for remotes like user@server:/path/to/project.git. With ssh remotes git executes remote commands, like git-receive-pack '/path/to/project.git' (this is stored in SSH_ORIGINAL_COMMAND environment variable for the curious) when doing something like git clone user@server:/path/to/project.git. Golem authorizes users so it must act before the actual git command runs. Key-based authentication is very popular and the .ssh/authorized_keys file allows a few possibilities to achieve what golem tries to do, so it seems a natural fit. Please note: golem won't work without key-based authentication, as it relies content placed in the .ssh/authorized_keys file.

Golem by default requires that you (control your SSHD's options and) set the users shell to golem-shell (wherever it is installed) that is "hosting" the repositories. With that setup golem can simply place lines like environment="GOLEM_USER=username" ssh-dss AAA... (where AAA... is the key) in the .ssh/authorized_keys file and golem-shell simply reads that environment variable. (Please note: SSHD by default does not permit changing environment variables, you have to enable it with setting PermitUserEnvironment to yes.) However this needs that the user's shell is set to golem-shell, so golem provides a configuration variable, if you can't or simply don't want to change the user's shell. When keys_file_use_command is true golem writes lines like command="/path/to/golem auth 'username'" ssh-dss AAA... instead. Please note:

Golem supports another configuration variable called keys_file_ssh_opts, which is simply placed after the environment="" or command="" block. If keys_file_use_command is false (using environment="") golem simply injects the string into the lines, however if keys_file_use_command is true and keys_file_ssh_opts is not set (is nil) golem uses {Golem::Command::UpdateKeysFile::SSH_OPTS_COMMAND_DEFAULT} (if it is not nil golem uses the configuration value). The reasoning behind this distinction is golem assumes you control your SSHD's settings if using environment="", but you may not (want to) set (global) restrictions when using command="". The final line looks something like environment="GOLEM_USER=username",ssh,opts ssh-dss AAA... or command="/path/to/golem auth 'username'",ssh,opts ssh-dss AAA....

Please note: golem does not overwrite the whole .ssh/authorized_keys file.

Access control

Golem's access control by default is very simple. It assumes a repository belongs to a single user, so it grants access to a given repository only to its owner. For a very basic setup this should be enough. However for more complex setup golem does not want to assume how you want to store your users and repositories, so it simply doesn't. You can fine tune your environment to suit your specific needs with overriding {Golem::Access.check} (its arguments are the username, the repository name and the git command to run (e.g. one of upload-pack, upload-archive and receive-pack)).

Golem's access control is done at the very beginning, before git-shell is run, so it's not suitable for per-branch or per-directory control. This can be achieved by hooks. You should check out { gitolite}, which supports exactly that (and more). If you want you can place { gitolite}'s hooks in golem's hooks_dir and achieve the same results (this requires deeper understanding of git, so please be aware).

Public access

Golem does not support providing public (read-only anonymous) access to git repositories as it relies on SSH's key-based authentication. However there are a couple of alternatives to solve this, with each having its pros and cons: { serving the repository as a static website}, { using GitWeb} or { using Git Daemon}.


Golem currently supports postgres and a static databases only, but it should be trivial to extend it (contributions are always welcome). At least users and repositories should have names, keys should have an attribute named key that is the whole key (e.g. cat

The {Golem::DB::Static static database} is suitable for small installations (where an rdbms would be an overkill), to use it simply write:

Golem.configure do |cfg|
  cfg.db = 'static'
  Golem::DB.setup do |db|
    db.add_user 'test_user'
    db.add_repository 'test_repository', 'test_user'
    db.add_key 'test_user', 'test_key'

The postgres database stores data in 3 tables (users, repositories, keys) by default, and can be used with setting the db variable to the postgres url (e.g. postgres://user:pw@host/db). A sample schema can be found in lib/golem/db/postgres.sql, and it is imported by {Golem::DB::Pg#setup} (please note: {Golem::DB.setup} forwards to it, should be called only once). A minimal setup for postgres would be:

Golem.configure do |cfg|
  cfg.db = "postgres://user:pwd@host/dbname"
  cfg.bin_dir = "/usr/local/bin"

A more complex setup with collaborators:

Golem.configure do |cfg|
  Golem::DB::Pg.class_eval do
    #add method to query collaborators
    def collaborators(opts = {})
      opts[:table] = "collaborators join users on"

    #add method to check if user is a collaborator of a given repository
    def collaborator?(user, repo)
      collaborators(:user_name => user, :repository_name => repo, :fields => :name).length > 0

    #override setup to add our collaborators table
    alias_method :setup_orig, :setup
    def setup
      @connection.exec("CREATE TABLE collaborators (user_name varchar(32) NOT NULL REFERENCES users (name), repository_name varchar(32) NOT NULL REFERENCES repositories (name), PRIMARY KEY (user_name, repository_name));")
  Golem::DB.class_eval do
    #add method proxy to check collaborator status
    def self.collaborator?(user, repo)
      db.collaborator?(user, repo)
  Golem::Access.class_eval do
    #override check to grant access to collaborators
    class << self; alias_method :check_orig, :check end
    def self.check(user, repo, gitcmd)
      Golem::DB.collaborator?(user, repo) || check_orig(user, repo, gitcmd)
  cfg.db = 'postgres://user:pwd@host/dbname'


Golem provides an executable, and supports a few commands to easily automate the administration:

  • auth: is used for authorization by sshd,
  • clear_repositories: clear old data (e.g. suitable for cron),
  • create_repository: create a repository manually (new repositories are created automatically by golem on first access),
  • delete_repository: delete a repository manually,
  • environment: list configuration variables,
  • save_config: save configuration variables,
  • setup_db: setup database schema (useful for postgres only),
  • update_hooks: update hooks in every repository,
  • update_keys_file: update the .ssh/authorized_keys file.

You can get details about commands running golem -h or --help.

Golem provides another executable called golem-shell, which is a convenience script that calls golem auth.

Contributing to golem

  • Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
  • Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
  • Fork the project
  • Start a feature/bugfix branch
  • Commit and push until you are happy with your contribution
  • Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
  • Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.


Copyright (c) 2011 PoTa. See LICENSE.txt for further details.