"hooklets" -- play nice with any number of site-local 'update' hooks
(yes, I made up the name. Deal with it!)
This commit is contained in:
parent
d74e58b5de
commit
0d1e05c7e1
74
contrib/update.detect-dup-pubkeys
Executable file
74
contrib/update.detect-dup-pubkeys
Executable file
|
@ -0,0 +1,74 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# update "hooklet" to detect duplicate public keys
|
||||||
|
|
||||||
|
# This particular hooklet also serves as an example for people writing others.
|
||||||
|
# [It should be quite easy to figure out what parts apply to any hooklet and
|
||||||
|
# what parts are specific to *this* hooklet and its function.]
|
||||||
|
|
||||||
|
# see hooks/common/update.secondary.sample for instructions on *enabling*
|
||||||
|
# hooklets
|
||||||
|
|
||||||
|
# a hooklet is called as follows:
|
||||||
|
# git-receive-pack --> 'update' --> 'update.secondary' --> this script
|
||||||
|
# note: the same three arguments that git passes to the update hook are passed
|
||||||
|
# along to each hooklet.
|
||||||
|
|
||||||
|
# the update hook, and therefore the hooklets, are called for *every* repo out
|
||||||
|
# there. If you want this hooklet to run only for certain repos, here's how:
|
||||||
|
[ "$GL_REPO" = "gitolite-admin" ] || exit 0
|
||||||
|
|
||||||
|
# superfluous, since update.secondary already did it, but I'd like to
|
||||||
|
# emphasise that all output MUST go to STDERR
|
||||||
|
exec >&2
|
||||||
|
|
||||||
|
# ----
|
||||||
|
|
||||||
|
# the main functionality of the hooklet starts here. In this one (and I
|
||||||
|
# suspect many others) we want to examine the actual files from the commit
|
||||||
|
# that was pushed.
|
||||||
|
|
||||||
|
# get the tip commit being pushed
|
||||||
|
sha=$3
|
||||||
|
|
||||||
|
# git sets this; and we don't want it at this point...
|
||||||
|
unset GIT_DIR
|
||||||
|
|
||||||
|
# paranoia
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# setup the temp area
|
||||||
|
export TMPDIR=$GL_REPO_BASE_ABS
|
||||||
|
export tmp=$(mktemp -d -t gl-internal-temp-repo.XXXXXXXXXX);
|
||||||
|
trap "rm -rf $tmp" EXIT;
|
||||||
|
|
||||||
|
# now get the files into $tmp.
|
||||||
|
# (note: if your task does not require the actual files, and you can
|
||||||
|
# manage with "git cat-file -s" and so on, then you may not even need a
|
||||||
|
# $tmp; you may be able to do it all right in the repo.git directory)
|
||||||
|
|
||||||
|
git archive $sha keydir | tar -C $tmp -xf -
|
||||||
|
# DO NOT try, say, 'GIT_WORK_TREE=$tmp git checkout $sha'. It'll screw up
|
||||||
|
# both the 'index' and 'HEAD' of the repo.git. Screwing up the index is
|
||||||
|
# BAD because now it goes out of sync with $GL_ADMINDIR. Think of a push
|
||||||
|
# that had a deleted pubkey but failed a hooklet for some reason. A
|
||||||
|
# subsequent push that fixes the error will now result in a $GL_ADMINDIR
|
||||||
|
# that still *has* that deleted pubkey!!
|
||||||
|
|
||||||
|
# And this is equally applicable to cases where you're using a
|
||||||
|
# post-receive or similar hook to live update a web site or something,
|
||||||
|
# which is a pretty common usage, I am given to understand.
|
||||||
|
|
||||||
|
cd $tmp
|
||||||
|
|
||||||
|
# ----
|
||||||
|
|
||||||
|
# *finally*, the actual check you need to do in this hook: look for duplicate
|
||||||
|
# pubkeys and exit 1 if dups are found
|
||||||
|
for f in `find keydir -name "*.pub"`
|
||||||
|
do
|
||||||
|
ssh-keygen -l -f "$f"
|
||||||
|
done | perl -ane '
|
||||||
|
die "$F[2] is a duplicate of $seen{$F[1]}\n" if $seen{$F[1]};
|
||||||
|
$seen{$F[1]} = $F[2];
|
||||||
|
'
|
|
@ -4,9 +4,7 @@
|
||||||
|
|
||||||
# Gitolite specific script to check "author email" field of every commit
|
# Gitolite specific script to check "author email" field of every commit
|
||||||
# pushed and to disallow if this email does not match the email that the
|
# pushed and to disallow if this email does not match the email that the
|
||||||
# user pushing is expected to have. Needs to be renamed to
|
# user pushing is expected to have.
|
||||||
# "update.secondary"; see gitolite docs for how to propagate this to all
|
|
||||||
# repos.
|
|
||||||
|
|
||||||
# Use without gitolite is also possible; just substitute your access
|
# Use without gitolite is also possible; just substitute your access
|
||||||
# control system's notion of "user" for the env var GL_USER in the code
|
# control system's notion of "user" for the env var GL_USER in the code
|
||||||
|
|
|
@ -148,6 +148,10 @@ if such a hook exists. People wishing to do exotic things on the server side
|
||||||
when the admin repo is pushed should see doc/shell-games.notes for how to
|
when the admin repo is pushed should see doc/shell-games.notes for how to
|
||||||
exploit this :-)
|
exploit this :-)
|
||||||
|
|
||||||
|
In addition, gitolite now contains the basic infrastructure to support
|
||||||
|
multiple such hooks without having to remember to chain them yourself. You
|
||||||
|
can look in `hooks/common/update.secondary.sample` for instructions.
|
||||||
|
|
||||||
Finally, these names (`update.secondary` and `post-update.secondary`) are
|
Finally, these names (`update.secondary` and `post-update.secondary`) are
|
||||||
merely the defaults. You can change them to anything you want; look in
|
merely the defaults. You can change them to anything you want; look in
|
||||||
conf/example.gitolite.rc for details.
|
conf/example.gitolite.rc for details.
|
||||||
|
|
|
@ -86,14 +86,14 @@ if (exists $repos{$ENV{GL_REPO}}{NAME_LIMITS}) {
|
||||||
my $log_refex = check_ref(\@allowed_refs, $ENV{GL_REPO}, (shift @refs), $att_acc);
|
my $log_refex = check_ref(\@allowed_refs, $ENV{GL_REPO}, (shift @refs), $att_acc);
|
||||||
check_ref (\@allowed_refs, $ENV{GL_REPO}, $_ , $att_acc) for @refs;
|
check_ref (\@allowed_refs, $ENV{GL_REPO}, $_ , $att_acc) for @refs;
|
||||||
|
|
||||||
# if we returned at all, all the checks succeeded, so we log the action and exit 0
|
# if we returned at all, all the checks succeeded. Check secondary hooks now
|
||||||
|
$UPDATE_CHAINS_TO ||= 'hooks/update.secondary';
|
||||||
|
( -f $UPDATE_CHAINS_TO or -l $UPDATE_CHAINS_TO )
|
||||||
|
and system ( $UPDATE_CHAINS_TO, @ARGV )
|
||||||
|
and die "$UPDATE_CHAINS_TO died\n";
|
||||||
|
|
||||||
|
# now log it and exit 0 so git can get on with it
|
||||||
log_it("", "$att_acc\t" . substr($oldsha, 0, 14) . "\t" . substr($newsha, 0, 14) .
|
log_it("", "$att_acc\t" . substr($oldsha, 0, 14) . "\t" . substr($newsha, 0, 14) .
|
||||||
"\t$reported_repo\t$ref\t$log_refex");
|
"\t$reported_repo\t$ref\t$log_refex");
|
||||||
|
|
||||||
# now chain to the local admin defined update hook, if present
|
|
||||||
$UPDATE_CHAINS_TO ||= 'hooks/update.secondary';
|
|
||||||
exec $UPDATE_CHAINS_TO, @ARGV
|
|
||||||
if -f $UPDATE_CHAINS_TO or -l $UPDATE_CHAINS_TO;
|
|
||||||
|
|
||||||
exit 0;
|
exit 0;
|
||||||
|
|
44
hooks/common/update.secondary.sample
Normal file
44
hooks/common/update.secondary.sample
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# driver script to run multiple update "hooklets". Each "hooklet" performs a
|
||||||
|
# specific (possibly site-local) check, and they *all* have to succeed for the
|
||||||
|
# push to succeed.
|
||||||
|
|
||||||
|
# HOW TO USE:
|
||||||
|
|
||||||
|
# (1) clone gitolite as you would for an upgrade (or install)
|
||||||
|
# (2) rename this file to remove the .sample extension
|
||||||
|
# (3) make the renamed file executable (chmod +x)
|
||||||
|
# (4) create a directory called update.secondary.d in hooks/common
|
||||||
|
# (5) copy all the update "hooklets" you want (like update.detect-dup-pubkeys)
|
||||||
|
# from contrib or wherever, to that directory
|
||||||
|
# (6) make them also executable (chmod +x)
|
||||||
|
# (7) install/upgrade gitolite as normal so all these files go to the server
|
||||||
|
|
||||||
|
# rules for writing a hooklet are in the sample hooklet called
|
||||||
|
# "update.detect-dup-pubkeys" in contrib
|
||||||
|
|
||||||
|
# ----
|
||||||
|
|
||||||
|
# NOTE: a hooklet runs under the same assumptions as the 'update' hook, so the
|
||||||
|
# starting directory must be maintained and arguments must be passed on.
|
||||||
|
|
||||||
|
[ -d hooks/update.secondary.d ] || exit 0
|
||||||
|
|
||||||
|
# all output from these "hooklets" must go to STDERR to avoid confusing the client
|
||||||
|
exec >&2
|
||||||
|
|
||||||
|
for i in hooks/update.secondary.d/*
|
||||||
|
do
|
||||||
|
[ -x "$i" ] || continue
|
||||||
|
# call the hooklet with the same arguments we got
|
||||||
|
"$i" "$@" || {
|
||||||
|
# hooklet failed; we need to log it...
|
||||||
|
echo hooklet $i failed
|
||||||
|
perl -I$GL_BINDIR -Mgitolite -e "log_it('hooklet $i failed')"
|
||||||
|
# ...and send back some non-zero exit code ;-)
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
done
|
||||||
|
|
||||||
|
exit 0
|
Loading…
Reference in a new issue