Instrucciones para un repositorio git …

… pasadas a limpio.

Hoy he tenido que ponerme manos a la obra para reconstruir mi repositorio git personal dado que empezaba a ser un poco caótico el acceso al mismo.

En esta entrada comencé hablando de ello y en esta otra amplié la información. Ahora veo que necesito una lista más ordenada y detallada del procedimiento.

Ojo: esta información sirve para un repositorio de un único usuario; si son varios es mejor echarle un vistazo a otro tipo de programas.

[toc]

Objetivos

  • Repositorio git para un único desarrollador.
  • Acceso de escritura seguro.
  • Acceso de lectura sencillo.

Requerimientos

  • Cuenta de usuario específica para gestionar el repositorio.
  • Paquetes: git y gitweb.
  • Scripts de mantenimiento del repositorio vía ssh.

Puesta en marcha

Se puede poner en marcha en dos partes: por una la gestión del propio repositorio en sí empleando SSH y git, lo que consigue accesos seguros de lectura y escritura; por otra el montaje del acceso vía web (con Apache y gitweb), que facilita mucho clonar los repositorios desde cualquier sitio sin comprometer la seguridad.

Creación de cuenta de usuario

$ sudo adduser --home /var/lib/git --no-create-home --shell /usr/bin/git-shell git
$ chown -R git.www-data /var/lib/git 

 

Scripts de mantenimiento

El programa git-shell sólo tiene acceso a los programas que aparezcan en el directorio ~/git-shell-commands y que tengan permisos de ejecución.

En el directorio /usr/share/doc/git/contrib se encuentran algunos y en la página Plan Zero otros.

create
#!/bin/sh

#
#       Stolen idea from 
#       http://planzero.org/blog/2012/10/24/hosting_an_admin-friendly_git_server_with_git-shell
#

# If the user is not root
#if [ "$USERNAME" != "root" ]
#then
#
#       # Dislpay a notice and stop
#       echo "Sorry, only root can use this command."
#       exit 1
#
#fi

# If no project name is given
if [ $# -eq 0 ]
then

        # Display usage and stop
        echo "Usage: create <project.git>"
        exit 1

fi

# Set the project name, adding .git if necessary# Check for errors
if [ $(echo "$fingerprint" | egrep -c '(R|D)SA') -eq 0 ]
then

 # Display the fingerprint error and clean up
 echo "Error: $fingerprint"
 rm $keyfile
 exit 1

fi

# Add the key to the authorised keys file and clean up
mkdir -p .ssh &&\
echo -n "no-agent-forwarding,no-port-forwarding,no-X11-forwarding " >> .ssh/authorized_keys &&\
cat $keyfile >> .ssh/authorized_keys
rm $keyfile

# Display the fingerprint for reference
echo "Success! Added a key with the following fingerprint:"
echo $fingerprint
project=$(echo "$*" | sed 's/\.git$\|$/.git/i')

# Create and initialise the project
mkdir "$project" && \
cd "$project" && \
git --bare init
description
#!/bin/sh

# If no project name is given
if [ $# -eq 0 ]
then

        # Display usage and stop
        echo "Usage: description <project.git>"
        exit 1
else
        REPO=$1.git
fi

if [ ! -d "$REPO" ]; then 
        echo "Repository $REPO not found"
        exit 1
else 
        echo "Current description: "
        cat $REPO/description
fi 

# Read the description
echo "Enter the new description:" 
read desc

if [ -z "$desc" ]; then 
        echo "Description not changed !"
else
        echo $desc > $REPO/description
        echo "Description updated"
fi

exit 0
addkey
#!/bin/sh

#
#       Stolen idea from 
#       http://planzero.org/blog/2012/10/24/hosting_an_admin-friendly_git_server_with_git-shell
#

# If the user is not root
#if [ "$USERNAME" != "root" ]
#then
#
#       # Dislpay a notice and stop
#       echo "Sorry, only root can use this command."
#       exit 1
#
#fi

# Read in the SSH key
echo "Input the key to be added:"
read key

# Place the key in a temporary file (it's hard to get ssh-keygen
# to read from stdin; <<< works for bash, but is non-posix)
keyfile=$(tempfile) &&\
echo "$key" > $keyfile

# Generate a fingerprint
fingerprint=$(ssh-keygen -lf $keyfile)

# Check for errors
if [ $(echo "$fingerprint" | egrep -c '(R|D)SA') -eq 0 ]
then

        # Display the fingerprint error and clean up
        echo "Error: $fingerprint"
        rm $keyfile
        exit 1

fi

# Add the key to the authorised keys file and clean up
mkdir -p .ssh &&\
echo -n "no-agent-forwarding,no-port-forwarding,no-X11-forwarding " >> .ssh/authorized_keys &&\
cat $keyfile >> .ssh/authorized_keys
rm $keyfile

# Display the fingerprint for reference
echo "Success! Added a key with the following fingerprint:"
echo $fingerprint

Interfaz web

Lo que pretendo instalando el programa gitweb es conseguir un acceso sencillo a los repositorios empleando un navegador web y, de paso, una manera de clonar los repositorios en máquinas donde puedo necesitarlos sin tener que complicarme la vida con accesos SSH de usuarios.

Es un programa escrito en Perl, flexible en su configuración y muy versátil. Está bastante bien documentado y ofrece ejemplos para instalaciones muy variadas.

Iba a decir que lo primero es elegir el esquema de URL para acceder al contenido, y es importante que sea sencillo de recordar, pero creo que es más conveniente decidir primero qué contenido queremos que sea accesible.

Lista de proyectos de gitweb

Si no se indica otra cosa la lista de proyectos que muestra el programa se crea recorriendo el directorio raíz de los repositorios (/var/lib/git). Como ésto puede ser demasiado abierto considero que es mejor crear una lista de proyectos a mostrar y añadir algún tipo de mecanismo a la cuenta SSH para cambiar el estatus entre público y privado.

La variable $projects_list contiene la ruta de un archivo de texto donde se listan, uno por línea, aquellos repositorios que queremos que sean públicos. El formato es un tanto riguroso pero muy sencillo y está descrito en la documentación. También conviene indicar la exportación sea lo más rigurosa posible por lo que esa parte de la configuración queda así.

$projects_list = "/var/www/html/git.astillas.net/repositories.txt";
$strict_export = 1;

 

El servidor web y los URL

Todas las indicaciones a continuación son para el servidor web Apache y teniendo en cuenta la baja carga que tendrá el repositorio. No está optimizado para accesos masivos.

Lo primero es determinar qué URL vamos a utilizar para acceder. En mi caso ya dispongo de un servidor virtual llamado git.astillas.net y lo que quiero es:

  1. Acceder al interfaz web empleando un URL simple: https://git.astillas.net.
  2. Clonar repositorios directamente y también con un URL sencillo: https://git.astillas.net/msat.git por ejemplo.

En Debian el paquete gitweb sitúa el programa principal en /usr/lib/cgi-bin/gitweb.cgi y los contenidos extras bajo /usr/share/gitweb/static de tal manera que es necesario emplear varias directivas para acceder a ellos. También será necesario activar en Apache la configuración de programas CGI del sistema (serve-cgi-bin.conf).

El directorio del servidor virtual será el propio de los repositorios git en /var/lib/git y el fragmento de la configuración es el siguiente:

<VirtualHost *:443>
        ServerName              git.astillas.net
        UseCanonicalName        on

        LogLevel info
        ErrorLog /var/log/apache2/git.astillas.net/error.log
        CustomLog /var/log/apache2/git.astillas.net/access.log combined
        CustomLog /var/log/apache2/git.astillas.net/agent.log agent
        CustomLog /var/log/apache2/git.astillas.net/referer.log referer

        # Conexión segura
        Include         /etc/apache2/conf.d/astillas-ssl.conf

        # Entorno para el programa
        SetEnv  GITWEB_CONFIG   /etc/gitweb.conf
        SetEnv  GIT_PROJECT_ROOT /var/lib/git
        SetEnv  GIT_HTTP_EXPORT_ALL

        # Directorio raíz y alias a recursos estáticos de gitweb
        DocumentRoot /var/lib/git
        <Directory /var/lib/git>
                Options +ExecCGI +FollowSymLinks
                Require all granted
        </Directory>
        #  Gitweb y git-http-backend
        ScriptAlias /   /usr/lib/git-core/git-http-backend/
        <Directory "/usr/lib/git-core">
                AllowOverride None
                Options +ExecCGI +FollowSymLinks
                Require all granted
        </Directory>

        ScriptAliasMatch \
         "(?x)^/(.*/(HEAD | \
          info/refs | \
           objects/(info/[^/]+ | \
           [0-9a-f]{2}/[0-9a-f]{38} | \
           pack/pack-[0-9a-f]{40}\.(pack|idx)) | \
           git-upload-pack))$" \
           /usr/lib/git-core/git-http-backend/$1/

        # turning on mod rewrite
        RewriteEngine on
        RewriteRule ^/$  /cgi-bin/gitweb.cgi [QSA,L,PT]
</VirtualHost>

El archivo que incluye astillas-ssl.conf define los parámetrros para la conexión segura con el servidor y no merece atención para este fin.

El resto emplea la directiva ScriptAliasMatch y mod_rewrite para asegurarse de que:

  1. Cuando se solicite una operación de clonado del repositorio o información concreta sobre su historial y demás se llame a un programa específico incluído con git: git-http-backend.
  2. Si no se pide nada concreto se cede el control a gitweb.cgi.

También se indica que en dos lugares concretos se pueden ejecutar scripts y algún que otro detalle más. Esto es necesario porque el paquete Debian sitúa en diferentes sitios (siguiendo su normativa) los ejecutables normales y los de CGI.

Un detalle final que queda bonito es añadir un alias al directorio donde residen los archivos estáticos del programa como hojas de estilo, imágenes y demás.

Recetario

 

Crear el repositorio

$ ssh git@servidor create repositorio.git

y añadirle una descripción para la vista web:

$ ssh git@servidor description repositorio.git 
Descrition:
xxxxxxxx
$

Clonar el repositorio

$ git clone https://servidor/repositorio.git 
$ git clone git@servidor:repositorio.git

Actualizar el repositorio

git push git@servidor:repositorio.git