Documentation: shared repository management in tutorial.

The branch policy script I outlined was improved and polished by
Carl and posted on the list twice since then.  It is a shame not
to pick it up, so replace the original outline in
howto/update-hook-example.txt with the latest from Carl.

Also talk about setting up git-shell to allow git-push/git-fetch
only SSH access to a shared repository host in the tutorial.

Signed-off-by: Junio C Hamano <junkio@cox.net>
This commit is contained in:
Junio C Hamano
2005-12-05 00:57:48 -08:00
parent eb0362a467
commit dc5f9239f7
2 changed files with 167 additions and 65 deletions

View File

@ -1,4 +1,4 @@
From: Junio C Hamano <junkio@cox.net>
From: Junio C Hamano <junkio@cox.net> and Carl Baldwin <cnb@fc.hp.com>
Subject: control access to branches.
Date: Thu, 17 Nov 2005 23:55:32 -0800
Message-ID: <7vfypumlu3.fsf@assigned-by-dhcp.cox.net>
@ -26,63 +26,137 @@ section of the documentation:
So if your policy is (1) always require fast-forward push
(i.e. never allow "git-push repo +branch:branch"), (2) you
have a list of users allowed to update each branch, and (3) you
do not let tags to be overwritten, then:
do not let tags to be overwritten, then you can use something
like this as your hooks/update script.
#!/bin/sh
# This is a sample hooks/update script, written by JC
# in his e-mail buffer, so naturally it is not tested
# but hopefully would convey the idea.
[jc: editorial note. This is a much improved version by Carl
since I posted the original outline]
umask 002
case "$1" in
refs/tags/*)
# No overwriting an existing tag
if test -f "$GIT_DIR/$1"
then
exit 1
fi
;;
refs/heads/*)
# No rebasing or rewinding
if expr "$2" : '0*$' >/dev/null
then
# creating a new branch
;
else
# updating -- make sure it is a fast forward
mb=`git-merge-base "$2" "$3"`
case "$mb,$2" in
"$2,$mb")
;; # fast forward -- happy
*)
exit 1 ;; # unhappy
esac
fi
;;
*)
# No funny refs allowed
exit 1
;;
esac
-- >8 -- beginning of script -- >8 --
# Is the user allowed to update it?
me=`id -u -n` ;# e.g. "junio"
while read head_pattern users
do
if expr "$1" : "$head_pattern" >/dev/null
then
case " $users " in
*" $me "*)
exit 0 ;; # happy
' * ')
exit 0 ;; # anybody
esac
fi
done
exit 1
#!/bin/bash
For the sake of simplicity, I assumed that you keep something
like this in $GIT_DIR/info/allowed-pushers file:
umask 002
# If you are having trouble with this access control hook script
# you can try setting this to true. It will tell you exactly
# why a user is being allowed/denied access.
verbose=false
# Default shell globbing messes things up downstream
GLOBIGNORE=*
function grant {
$verbose && echo >&2 "-Grant- $1"
echo grant
exit 0
}
function deny {
$verbose && echo >&2 "-Deny- $1"
echo deny
exit 1
}
function info {
$verbose && echo >&2 "-Info- $1"
}
# Implement generic branch and tag policies.
# - Tags should not be updated once created.
# - Branches should only be fast-forwarded.
case "$1" in
refs/tags/*)
[ -f "$GIT_DIR/$1" ] &&
deny >/dev/null "You can't overwrite an existing tag"
;;
refs/heads/*)
# No rebasing or rewinding
if expr "$2" : '0*$' >/dev/null; then
info "The branch '$1' is new..."
else
# updating -- make sure it is a fast forward
mb=$(git-merge-base "$2" "$3")
case "$mb,$2" in
"$2,$mb") info "Update is fast-forward" ;;
*) deny >/dev/null "This is not a fast-forward update." ;;
esac
fi
;;
*)
deny >/dev/null \
"Branch is not under refs/heads or refs/tags. What are you trying to do?"
;;
esac
# Implement per-branch controls based on username
allowed_users_file=$GIT_DIR/info/allowed-users
username=$(id -u -n)
info "The user is: '$username'"
if [ -f "$allowed_users_file" ]; then
rc=$(cat $allowed_users_file | grep -v '^#' | grep -v '^$' |
while read head_pattern user_patterns; do
matchlen=$(expr "$1" : "$head_pattern")
if [ "$matchlen" == "${#1}" ]; then
info "Found matching head pattern: '$head_pattern'"
for user_pattern in $user_patterns; do
info "Checking user: '$username' against pattern: '$user_pattern'"
matchlen=$(expr "$username" : "$user_pattern")
if [ "$matchlen" == "${#username}" ]; then
grant "Allowing user: '$username' with pattern: '$user_pattern'"
fi
done
deny "The user is not in the access list for this branch"
fi
done
)
case "$rc" in
grant) grant >/dev/null "Granting access based on $allowed_users_file" ;;
deny) deny >/dev/null "Denying access based on $allowed_users_file" ;;
*) ;;
esac
fi
allowed_groups_file=$GIT_DIR/info/allowed-groups
groups=$(id -G -n)
info "The user belongs to the following groups:"
info "'$groups'"
if [ -f "$allowed_groups_file" ]; then
rc=$(cat $allowed_groups_file | grep -v '^#' | grep -v '^$' |
while read head_pattern group_patterns; do
matchlen=$(expr "$1" : "$head_pattern")
if [ "$matchlen" == "${#1}" ]; then
info "Found matching head pattern: '$head_pattern'"
for group_pattern in $group_patterns; do
for groupname in $groups; do
info "Checking group: '$groupname' against pattern: '$group_pattern'"
matchlen=$(expr "$groupname" : "$group_pattern")
if [ "$matchlen" == "${#groupname}" ]; then
grant "Allowing group: '$groupname' with pattern: '$group_pattern'"
fi
done
done
deny "None of the user's groups are in the access list for this branch"
fi
done
)
case "$rc" in
grant) grant >/dev/null "Granting access based on $allowed_groups_file" ;;
deny) deny >/dev/null "Denying access based on $allowed_groups_file" ;;
*) ;;
esac
fi
deny >/dev/null "There are no more rules to check. Denying access"
-- >8 -- end of script -- >8 --
This uses two files, $GIT_DIR/info/allowed-users and
allowed-groups, to describe which heads can be pushed into by
whom. The format of each file would look like this:
refs/heads/master junio
refs/heads/cogito$ pasky
@ -91,15 +165,8 @@ like this in $GIT_DIR/info/allowed-pushers file:
refs/tags/v[0-9]* junio
With this, Linus can push or create "bw/penguin" or "bw/zebra"
or "bw/panda" branches, Pasky can do only "cogito", and I can do
master branch and make versioned tags. And anybody can do
tmp/blah branches. This assumes all the users are in a single
group that can write into $GIT_DIR/ and underneath.
or "bw/panda" branches, Pasky can do only "cogito", and JC can
do master branch and make versioned tags. And anybody can do
tmp/blah branches.
------------