Summary: much as I did not want to use "excludes", I guess if we don't put the code in "master" it's OK to at least *write* (and test) the code! See the example config file for how to use it. See "design choices" section in the "faq, tips, etc" document for how it works.
108 lines
3.8 KiB
Perl
Executable file
108 lines
3.8 KiB
Perl
Executable file
#!/usr/bin/perl
|
|
|
|
use strict;
|
|
use warnings;
|
|
|
|
# === update ===
|
|
# this is gitolite's update hook
|
|
|
|
# part of the gitolite (GL) suite
|
|
|
|
# how run: via git, being copied as .git/hooks/update in every repo
|
|
# when: every push
|
|
# input:
|
|
# - see man githooks for STDIN
|
|
# - uses the compiled config file to get permissions info
|
|
# output: based on permissions etc., exit 0 or 1
|
|
# security:
|
|
# - none
|
|
|
|
# robustness:
|
|
|
|
# other notes:
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# common definitions
|
|
# ----------------------------------------------------------------------------
|
|
|
|
our ($GL_CONF_COMPILED, $PERSONAL);
|
|
our %repos;
|
|
|
|
# we should already have the GL_RC env var set when we enter this hook
|
|
die "parse $ENV{GL_RC} failed: " . ($! or $@) unless do $ENV{GL_RC};
|
|
# then "do" the compiled config file, whose name we now know
|
|
die "parse $GL_CONF_COMPILED failed: " . ($! or $@) unless do $GL_CONF_COMPILED;
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# start...
|
|
# ----------------------------------------------------------------------------
|
|
|
|
my $ref = shift;
|
|
my $oldsha = shift;
|
|
my $newsha = shift;
|
|
my $merge_base = '0' x 40;
|
|
# compute a merge-base if both SHAs are non-0, else leave it as '0'x40
|
|
# (i.e., for branch create or delete, merge_base == '0'x40)
|
|
chomp($merge_base = `git merge-base $oldsha $newsha`)
|
|
unless $oldsha eq '0' x 40
|
|
or $newsha eq '0' x 40;
|
|
|
|
# some of this is from an example hook in Documentation/howto of git.git, with
|
|
# some variations
|
|
|
|
# what are you trying to do? (is it 'W' or '+'?)
|
|
my $perm = 'W';
|
|
# rewriting a tag is considered a rewind, in terms of permissions
|
|
$perm = '+' if $ref =~ m(refs/tags/) and $oldsha ne ('0' x 40);
|
|
# non-ff push to ref
|
|
# notice that ref delete looks like a rewind, as it should
|
|
$perm = '+' if $oldsha ne $merge_base;
|
|
|
|
my @allowed_refs;
|
|
# personal stuff -- right at the start in the new regime, I guess!
|
|
push @allowed_refs, { "$PERSONAL/$ENV{GL_USER}/" => "RW+" } if $PERSONAL;
|
|
# we want specific perms to override @all, so they come first
|
|
push @allowed_refs, @ { $repos{$ENV{GL_REPO}}{$ENV{GL_USER}} || [] };
|
|
push @allowed_refs, @ { $repos{$ENV{GL_REPO}}{'@all'} || [] };
|
|
|
|
my $refex = '';
|
|
|
|
# check one ref
|
|
sub check_ref {
|
|
|
|
# normally, the $ref will be whatever ref the commit is trying to update
|
|
# (like refs/heads/master or whatever). At least one of the refexes that
|
|
# pertain to this user must match this ref **and** the corresponding
|
|
# permission must also match the action (W or +) being attempted. If none
|
|
# of them match, the access is denied.
|
|
|
|
# Notice that the function DIES!!! Any future changes that require more
|
|
# work to be done *after* this, even on failure, can start using return
|
|
# codes etc., but for now we're happy to just die.
|
|
|
|
my $ref = shift;
|
|
for my $ar (@allowed_refs) {
|
|
$refex = (keys %$ar)[0];
|
|
# refex? sure -- a regex to match a ref against :)
|
|
next unless $ref =~ /$refex/;
|
|
die "$perm $ref $ENV{GL_USER} DENIED by $refex\n" if $ar->{$refex} eq '-';
|
|
|
|
# as far as *this* ref is concerned we're ok
|
|
return if ($ar->{$refex} =~ /\Q$perm/);
|
|
}
|
|
die "$perm $ref $ENV{GL_REPO} $ENV{GL_USER} DENIED by fallthru\n";
|
|
}
|
|
|
|
# and in this version, we have only one ref to check
|
|
check_ref($ref);
|
|
|
|
# if we returned at all, the check succeeded, so we log the action and exit 0
|
|
|
|
# logging note: if log failure isn't important enough to block pushes, get rid
|
|
# of all the error checking
|
|
open my $log_fh, ">>", $ENV{GL_LOG} or die "open log failed: $!\n";
|
|
print $log_fh "$ENV{GL_TS} $perm\t" .
|
|
substr($oldsha, 0, 14) . "\t" . substr($newsha, 0, 14) .
|
|
"\t$ENV{GL_REPO}\t$ref\t$ENV{GL_USER}\t$refex\n";
|
|
close $log_fh or die "close log failed: $!\n";
|
|
exit 0;
|