Skip to content

Instantly share code, notes, and snippets.

@adrianlzt adrianlzt/pre-receive Secret
Last active Dec 14, 2016

Embed
What would you like to do?
#!/usr/bin/env python
"""
Este git hook pre-receive comprueba si el usuario que hace push esta presente
en el array de key "dsmctools" dentro del fichero /usuarios.json.
En este caso, puede hacer push de cualquier fichero.
Si no pertenece a este grupo, se comprueba el path de los ficheros pusheados,
dando por hecho que el primer directorio es el nombre del proyecto.
Se comprueba si el usuario pertenece al dicho proyecto (array con clave el
nombre del proyecto).
"""
import sys
import os
import subprocess
import json
def git(args, **kwargs):
environ = os.environ.copy()
if 'repo' in kwargs:
environ['GIT_DIR'] = kwargs['repo']
if 'work' in kwargs:
environ['GIT_WORK_TREE'] = kwargs['work']
proc = subprocess.Popen(args, stdout=subprocess.PIPE, env=environ)
return proc.communicate()
def get_changed_files(base, commit, ref, **kw):
"""
Obtenemos los ficheros modificados entre el los commit 'base' y 'commit'
Si base es 00000... es que tenemos una rama nueva, y compararemos 'commit' con el commit anterior al primer commit de la rama
"""
results = ""
if base == "0000000000000000000000000000000000000000":
(results2, code) = git(('git', 'rev-list', commit, '--not', '--branches=*'), **kw)
lista_commits = results2.decode("utf-8").strip().split('\n')
(results, code) = git(('git', 'diff', '--numstat', '--name-only', "%s^..%s" % (lista_commits[-1], lista_commits[0])), **kw)
else:
(results, code) = git(('git', 'diff', '--numstat', '--name-only', "%s..%s" % (base, commit)), **kw)
return results.decode("utf-8").strip().split('\n')
def get_new_file(filename, commit):
(results, code) = git(('git', 'show', '%s:%s' % (commit, filename)))
return results.decode("utf-8")
def get_permissions():
(results, code) = git(('git', 'show', '%s:%s' % ("HEAD", "usuarios.json")))
permData = json.loads(results.decode("utf-8"))
return permData
def check_if_user_can_modify_file(user, git_file):
try:
projects = get_permissions()
except Exception as ex:
# En caso de fallo no contemplado, dejamos pushear
print("Excepcion leyendo el fichero de permissions: %s" % ex)
return True
# Si el usuario pertenece al grupo dsmctools, paso libre
try:
projects.get("dsmctools").index(user)
print("Perteneces a DSMC Tools. Edicion libre")
return True
except ValueError as ex:
# El usuario no pertenece al grupo dsmctools
pass
except AttributeError as ex:
# No existe el grupo dsmctools
pass
except Exception as ex:
# En caso de fallo no contemplado, dejamos pushear
print("Excepcion comprobando si un usuario pertenece a dsmctools: " + ex)
return True
# Obtenemos el directorio (proyecto) del fichero que se esta modificando
project = git_file.split("/")[0]
try:
projects.get(project).index(user)
return True
except ValueError as ex:
# El usuario no pertenece al grupo del fichero que quiere modificar
pass
except AttributeError as ex:
# No existe el grupo para ese proyecto
print("Pedir a dsmc.tools@tid.es que se cree el mapeo para este proyecto")
pass
print("Lo siento, pero tu usuario no tiene permisos para editar el fichero '" + git_file + "'")
return False
if os.environ['GITHUB_REPO_NAME'] != "dsmc/dsmc-monitoring":
print("Has configurado el pre-receive hook para dsmc/dsmc-monitoring. Seguramente te hayas equivocado")
sys.exit(0)
repo = os.getcwd()
basedir = os.path.join(repo, "..")
line = sys.stdin.read()
(base, commit, ref) = line.strip().split()
#print("base: ", base)
#print("commit: ", commit)
#print("ref: ", ref)
modified = get_changed_files(base, commit, ref)
#print("Ficheros modificados: %s" % modified)
user = os.environ['GITHUB_USER_LOGIN']
# Si no es github enterprise usar os.environ['USER']
print("Chequeando permisos de push para el usuario '%s'" % user)
for fname in modified:
if not check_if_user_can_modify_file(user, fname):
sys.exit(1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.