Подтвердить что ты не робот

Предотвращать людей от нажатия git commit с другим именем автора?

В git каждый пользователь должен указать правильного автора в своем локальном файле конфигурации git. Когда они нажимают на централизованный открытый репозиторий, сообщения фиксации в репозитории будут иметь имена авторов, которые они использовали при передаче в свой собственный репозиторий.

Существует ли способ, чтобы использовать набор известных авторов для коммитов? "Центральный" репозиторий будет доступен через ssh.

Я знаю, что это осложняется тем, что некоторые люди могут подталкивать фиксации, сделанные другими. Конечно, вы должны также разрешать людям, которым вы доверяете, нажимать на свои репозитории, но было бы замечательно, если бы здесь был способ предотвратить ошибку пользователя.

Есть ли простое решение этой проблемы в git?

4b9b3361

Ответ 1

Мы используем следующее, чтобы предотвратить случайные ошибки неизвестного автора (например, при быстром фиксации с сервера клиента или что-то в этом роде). Его следует поместить в .git/hooks/pre-receive и сделать исполняемым.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import subprocess
from itertools import islice, izip
import sys

old, new, branch = sys.stdin.read().split()

authors = {
    "John Doe": "[email protected]"
}

proc = subprocess.Popen(["git", "rev-list", "--pretty=format:%an%n%ae%n", "%s..%s" % (old, new)], stdout=subprocess.PIPE)
data = [line.strip() for line in proc.stdout.readlines() if line.strip()]

def print_error(commit, author, email, message):
    print "*" * 80
    print "ERROR: Unknown Author!"
    print "-" * 80
    proc = subprocess.Popen(["git", "rev-list", "--max-count=1", "--pretty=short", commit], stdout=subprocess.PIPE)
    print proc.stdout.read().strip()
    print "*" * 80
    raise SystemExit(1)

for commit, author, email in izip(islice(data, 0, None, 3), islice(data, 1, None, 3), islice(data, 2, None, 3)):
    _, commit_hash = commit.split()
    if not author in authors:
        print_error(commit_hash, author, email, "Unknown Author")
    elif authors[author] != email:
        print_error(commit_hash, author, email, "Unknown Email")

Ответ 2

Используйте крюк PRE-RECEIVE (подробнее см. githooks (5)). Там вы получите старый sha и новый sha для каждого обновленного обновления. И можете легко перечислить изменения и проверить, что у них есть собственный автор (git rev-list --pretty = format: "% an% ae% n" oldsha..newsha).

Вот пример script:

#!/bin/bash
#
# This pre-receive hooks checks that all new commit objects
# have authors and emails with matching entries in the files
# valid-emails.txt and valid-names.txt respectively.
#
# The valid-{emails,names}.txt files should contain one pattern per
# line, e.g:
#
# ^.*@0x63.nu$
# ^[email protected]$
#
# To just ensure names are just letters the following pattern
# could be used in valid-names.txt:
# ^[a-zA-Z ]*$
#


NOREV=0000000000000000000000000000000000000000

while read oldsha newsha refname ; do
    # deleting is always safe
    if [[ $newsha == $NOREV ]]; then
    continue
    fi

    # make log argument be "..$newsha" when creating new branch
    if [[ $oldsha == $NOREV ]]; then
    revs=$newsha
    else
    revs=$oldsha..$newsha
    fi
    echo $revs
    git log --pretty=format:"%h %ae %an%n" $revs | while read sha email name; do
    if [[ ! $sha ]]; then
        continue
    fi
        grep -q -f valid-emails.txt <<<"$email" || {
            echo "Email address '$email' in commit $sha not registred when updating $refname"
            exit 1
        }
        grep -q -f valid-names.txt <<<"$name" || {
            echo "Name '$name' in commit $sha not registred when updating $refname"
            exit 1
        }
    done
done

Ответ 3

Мы используем Gitlab, и поэтому имеет смысл утверждать авторов против членов группы Gitlab.

Следующий script (основанный на ответе @dsvensson), который должен быть установлен как предварительный прием, делает именно это:

from __future__ import print_function
from __future__ import unicode_literals

import sys
import os
import subprocess
import urllib2
import json
import contextlib
import codecs
from itertools import islice, izip

GITLAB_SERVER = 'https://localhost'
GITLAB_TOKEN = 'SECRET'
GITLAB_GROUP = 4
EMAIL_DOMAIN = 'example.com'

def main():
    commits = get_commits_from_push()
    authors = get_gitlab_group_members()
    for commit, author, email in commits:
        if author not in authors:
            die('Unknown author', author, commit, authors)
        if email != authors[author]:
            die('Unknown email', email, commit, authors)

def get_commits_from_push():
    old, new, branch = sys.stdin.read().split()
    rev_format = '--pretty=format:%an%n%ae'
    command = ['git', 'rev-list', rev_format, '{0}..{1}'.format(old, new)]
    # branch delete, let it through
    if new == '0000000000000000000000000000000000000000':
        sys.exit(0)
    # new branch
    if old == '0000000000000000000000000000000000000000':
        command = ['git', 'rev-list', rev_format, new, '--not', '--branches=*']
    output = subprocess.check_output(command)
    commits = [line.strip() for line in unicode(output, 'utf-8').split('\n') if line.strip()]
    return izip(islice(commits, 0, None, 3),
            islice(commits, 1, None, 3),
            islice(commits, 2, None, 3))

def get_gitlab_group_members():
    url = '{0}/api/v3/groups/{1}/members'.format(GITLAB_SERVER, GITLAB_GROUP)
    headers = {'PRIVATE-TOKEN': GITLAB_TOKEN}
    request = urllib2.Request(url, None, headers)
    with contextlib.closing(urllib2.urlopen(request)) as response:
        members = json.load(response)
    return dict((member['name'], '{}@{}'.format(member['username'], EMAIL_DOMAIN))
        for member in members)

def die(reason, invalid_value, commit, authors):
    message = []
    message.append('*' * 80)
    message.append("ERROR: {0} '{1}' in {2}"
            .format(reason, invalid_value, commit))
    message.append('-' * 80)
    message.append('Allowed authors and emails:')
    print('\n'.join(message), file=sys.stderr)
    for name, email in authors.items():
        print(u"  '{0} <{1}>'".format(name, email), file=sys.stderr)
    sys.exit(1)

def set_locale(stream):
    return codecs.getwriter('utf-8')(stream)

if __name__ == '__main__':
    # avoid Unicode errors in output
    sys.stdout = set_locale(sys.stdout)
    sys.stderr = set_locale(sys.stderr)

    # you may want to skip HTTPS certificate validation:
    #  import ssl
    #  if hasattr(ssl, '_create_unverified_context'):
    #    ssl._create_default_https_context = ssl._create_unverified_context

    main()

См. GitLab custom Git hooks docs для инструкций по установке.

Только get_gitlab_group_members() является специфичным для Gitlab, другая логика применяется к любому методу pre-receive (включая обработку удалений и созданий ветвей).

script теперь доступен в GitHub, пожалуйста, не стесняйтесь отправлять запросы на загрузку для любых ошибок/улучшений.

Ответ 4

Что вы можете сделать, это создать кучу разных учетных записей пользователей, поместить их в одну группу и предоставить этой группе возможность записи в репозиторий. Затем вы сможете написать простой входящий крючок, который проверяет, является ли пользователь, выполняющий script, таким же, как пользователь в наборе изменений.

Я никогда не делал этого, потому что я доверяю парням, которые проверяют код в своих репозиториях, но если есть способ, возможно, тот, который был описан выше.

Ответ 5

git первоначально не был предназначен для работы как svn с большим центральным хранилищем. Возможно, вы можете тянуть от людей по мере необходимости и отказываться от тяги, если их автор задает неточно?

Ответ 6

Если вы хотите управлять правами на интернет, обратившись к репо git, я предлагаю вам взглянуть на Gitosis, а не взбивать свои собственные, Идентификация предоставляется частным/открытым парам ключей.

Прочтите текст чтобы он был здесь.