NAME-based restrictions
Gitolite allows you to restrict changes by file/dir name. The syntax for this used "PATH/" as a prefix to denote such file/dir patterns. This has now been changed to "NAME/" because PATH is potentially confusing. While this is technically a backward-incompatible change, the feature itself was hitherto undocumented, and only a few people were using it, so I guess it's not that bad... Also added documentation now.
This commit is contained in:
parent
ab3c861241
commit
7124faa9f3
|
@ -165,6 +165,40 @@ repo git
|
||||||
# looking for (`W` or `+`), or a minus (`-`), results in success, or failure,
|
# looking for (`W` or `+`), or a minus (`-`), results in success, or failure,
|
||||||
# respectively. A fallthrough also results in failure
|
# respectively. A fallthrough also results in failure
|
||||||
|
|
||||||
|
# FILE/DIR NAME BASED RESTRICTIONS
|
||||||
|
# --------------------------------
|
||||||
|
|
||||||
|
# Here's a hopefully self-explanatory example. Assume the project has the
|
||||||
|
# following contents at the top level: a README, a "doc/" directory, and an
|
||||||
|
# "src/" directory.
|
||||||
|
|
||||||
|
repo foo
|
||||||
|
RW+ = lead_dev # rule 1
|
||||||
|
RW = dev1 dev2 dev3 dev4 # rule 2
|
||||||
|
|
||||||
|
RW NAME/ = lead_dev # rule 3
|
||||||
|
RW NAME/doc/ = dev1 dev2 # rule 4
|
||||||
|
RW NAME/src/ = dev1 dev2 dev3 dev4 # rule 5
|
||||||
|
|
||||||
|
# Notes
|
||||||
|
|
||||||
|
# - the "NAME/" is part of the syntax; think of it as a keyword if you like
|
||||||
|
|
||||||
|
# - file/dir NAME-based restrictions are *in addition* to normal (branch-name
|
||||||
|
# based) restrictions; they are not a *replacement* for them. This is why
|
||||||
|
# rule #2 (or something like it, maybe with a more specific branch-name) is
|
||||||
|
# needed; without it, dev1/2/3/4 cannot push any branches.
|
||||||
|
|
||||||
|
# - if a repo has *any* NAME/ rules, then NAME-based restrictions are checked
|
||||||
|
# for *all* users. This is why rule 3 is needed, even though we don't
|
||||||
|
# actually have any NAME-based restrictions on lead_dev. Notice the pattern
|
||||||
|
# on rule 3.
|
||||||
|
|
||||||
|
# - *each* file touched by the commits being pushed is checked against those
|
||||||
|
# rules. So, lead_dev can push changes to any files, dev1/2 can push
|
||||||
|
# changes to files in "doc/" and "src/" (but not the top level README), and
|
||||||
|
# dev3/4 can only push changes to files in "src/".
|
||||||
|
|
||||||
# GITWEB AND DAEMON STUFF
|
# GITWEB AND DAEMON STUFF
|
||||||
# -----------------------
|
# -----------------------
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ In this document:
|
||||||
* differences from gitosis
|
* differences from gitosis
|
||||||
* simpler syntax
|
* simpler syntax
|
||||||
* two levels of access rights checking
|
* two levels of access rights checking
|
||||||
|
* file/dir NAME based restrictions
|
||||||
* error checking the config file
|
* error checking the config file
|
||||||
* delegating parts of the config file
|
* delegating parts of the config file
|
||||||
* easier to specify gitweb "description" and gitweb/daemon access
|
* easier to specify gitweb "description" and gitweb/daemon access
|
||||||
|
@ -235,6 +236,15 @@ any of the refexes match, the push succeeds. If none of them match, it fails.
|
||||||
Gitolite also allows "exclude" or "deny" rules. See later in this document
|
Gitolite also allows "exclude" or "deny" rules. See later in this document
|
||||||
for details.
|
for details.
|
||||||
|
|
||||||
|
#### file/dir NAME based restrictions
|
||||||
|
|
||||||
|
In addition to branch-name based restrictions, gitolite also allows you to
|
||||||
|
restrict what files or directories can be involved in changes being pushed.
|
||||||
|
This basically uses `git diff --name-only` to obtain the list of files being
|
||||||
|
changed, treating each filename as a "ref" to be matched.
|
||||||
|
|
||||||
|
Please see `conf/example.conf` for syntax and examples.
|
||||||
|
|
||||||
#### error checking the config file
|
#### error checking the config file
|
||||||
|
|
||||||
gitosis does not do any. I just found out that if you mis-spell `members` as
|
gitosis does not do any. I just found out that if you mis-spell `members` as
|
||||||
|
|
|
@ -200,9 +200,9 @@ sub parse_conf_file
|
||||||
|
|
||||||
# if no ref is given, this PERM applies to all refs
|
# if no ref is given, this PERM applies to all refs
|
||||||
@refs = qw(refs/.*) unless @refs;
|
@refs = qw(refs/.*) unless @refs;
|
||||||
# fully qualify refs that dont start with "refs/" or "PATH/";
|
# fully qualify refs that dont start with "refs/" or "NAME/";
|
||||||
# prefix them with "refs/heads/"
|
# prefix them with "refs/heads/"
|
||||||
@refs = map { m(^(refs|PATH)/) or s(^)(refs/heads/); $_ } @refs;
|
@refs = map { m(^(refs|NAME)/) or s(^)(refs/heads/); $_ } @refs;
|
||||||
|
|
||||||
# expand the user list, unless it is just "@all"
|
# expand the user list, unless it is just "@all"
|
||||||
@users = expand_list ( @users )
|
@users = expand_list ( @users )
|
||||||
|
@ -239,13 +239,13 @@ sub parse_conf_file
|
||||||
# for 2nd level check, store each "ref, perms" pair in order
|
# for 2nd level check, store each "ref, perms" pair in order
|
||||||
for my $ref (@refs)
|
for my $ref (@refs)
|
||||||
{
|
{
|
||||||
# checking PATH based restrictions is expensive for
|
# checking NAME based restrictions is expensive for
|
||||||
# the update hook (see the changes to src/hooks/update
|
# the update hook (see the changes to src/hooks/update
|
||||||
# in this commit for why) so we would *very* much like
|
# in this commit for why) so we would *very* much like
|
||||||
# to avoid doing it for the large majority of repos
|
# to avoid doing it for the large majority of repos
|
||||||
# that do *not* use PATH limits. Setting a flag that
|
# that do *not* use NAME limits. Setting a flag that
|
||||||
# can be checked right away will help us do that
|
# can be checked right away will help us do that
|
||||||
$repos{$repo}{PATH_LIMITS} = 1 if $ref =~ /^PATH\//;
|
$repos{$repo}{NAME_LIMITS} = 1 if $ref =~ /^NAME\//;
|
||||||
push @{ $repos{$repo}{$user} }, { $ref => $perms }
|
push @{ $repos{$repo}{$user} }, { $ref => $perms }
|
||||||
unless $rurp_seen{$repo}{$user}{$ref}{$perms}++;
|
unless $rurp_seen{$repo}{$user}{$ref}{$perms}++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,12 +65,12 @@ push @allowed_refs, @ { $repos{$ENV{GL_REPO}}{'@all'} || [] };
|
||||||
# prepare the list of refs to be checked
|
# prepare the list of refs to be checked
|
||||||
|
|
||||||
# previously, we just checked $ref -- the ref being updated, which is passed
|
# previously, we just checked $ref -- the ref being updated, which is passed
|
||||||
# to us by git (see man githooks). Now we also have to treat each PATH being
|
# to us by git (see man githooks). Now we also have to treat each NAME being
|
||||||
# updated as a potential "ref" and check that, if PATH-based restrictions have
|
# updated as a potential "ref" and check that, if NAME-based restrictions have
|
||||||
# been specified
|
# been specified
|
||||||
|
|
||||||
my @refs = ($ref); # the first ref to check is the real one
|
my @refs = ($ref); # the first ref to check is the real one
|
||||||
if (exists $repos{$ENV{GL_REPO}}{PATH_LIMITS}) {
|
if (exists $repos{$ENV{GL_REPO}}{NAME_LIMITS}) {
|
||||||
# this is special to git -- the hash of an empty tree
|
# this is special to git -- the hash of an empty tree
|
||||||
my $empty='4b825dc642cb6eb9a060e54bf8d69288fbee4904';
|
my $empty='4b825dc642cb6eb9a060e54bf8d69288fbee4904';
|
||||||
# well they're not really "trees" but $empty is indeed the empty tree so
|
# well they're not really "trees" but $empty is indeed the empty tree so
|
||||||
|
@ -78,7 +78,7 @@ if (exists $repos{$ENV{GL_REPO}}{PATH_LIMITS}) {
|
||||||
# diff' only wants trees
|
# diff' only wants trees
|
||||||
my $oldtree = $oldsha eq '0' x 40 ? $empty : $oldsha;
|
my $oldtree = $oldsha eq '0' x 40 ? $empty : $oldsha;
|
||||||
my $newtree = $newsha eq '0' x 40 ? $empty : $newsha;
|
my $newtree = $newsha eq '0' x 40 ? $empty : $newsha;
|
||||||
push @refs, map { chomp; s/^/PATH\//; $_; } `git diff --name-only $oldtree $newtree`;
|
push @refs, map { chomp; s/^/NAME\//; $_; } `git diff --name-only $oldtree $newtree`;
|
||||||
}
|
}
|
||||||
|
|
||||||
my $refex = '';
|
my $refex = '';
|
||||||
|
@ -111,7 +111,7 @@ sub check_ref {
|
||||||
|
|
||||||
# and in this version, we have many "refs" to check. The one we print in the
|
# and in this version, we have many "refs" to check. The one we print in the
|
||||||
# log is the *first* one (which is a *real* ref, like refs/heads/master),
|
# log is the *first* one (which is a *real* ref, like refs/heads/master),
|
||||||
# while all the rest (if they exist) are like PATH/something. So we do the
|
# while all the rest (if they exist) are like NAME/something. So we do the
|
||||||
# first one separately to capture it, then run the rest (if any)
|
# first one separately to capture it, then run the rest (if any)
|
||||||
my $log_refex = check_ref(shift @refs);
|
my $log_refex = check_ref(shift @refs);
|
||||||
check_ref($_) for @refs;
|
check_ref($_) for @refs;
|
||||||
|
|
Loading…
Reference in a new issue