separating "push" from "create"
This is what I *should* have done back then; thanks to Jeff Mitchell for pointing out a problem with the old method. The old one is *definitely* a kludge. <shamefaced grin>
This commit is contained in:
parent
78c8caa24c
commit
a430cc57c7
|
@ -72,13 +72,15 @@
|
||||||
# start line:
|
# start line:
|
||||||
# repo [one or more repos and/or repo groups]
|
# repo [one or more repos and/or repo groups]
|
||||||
# followed by one or more permissions lines:
|
# followed by one or more permissions lines:
|
||||||
# (C|R|RW|RW+|RWD|RW+D) [zero or more refexes] = [one or more users]
|
# (C|R|RW|RW+|RWC|RW+C|RWD|RW+D|RWCD|RW+CD) [zero or more refexes] = [one or more users]
|
||||||
|
|
||||||
# there are 6 types of permissions: R, RW, and RW+ are simple (the "+" means
|
# there are 6 types of permissions: R, RW, and RW+ are simple (the "+" means
|
||||||
# permission to "rewind" -- force push a non-fast forward to -- a branch).
|
# permission to "rewind" -- force push a non-fast forward to -- a branch).
|
||||||
# The C permission is described in doc/4-wildcard-repositories.mkd. The D
|
# The *standalone* C permission pertains to creating a REPO and is described
|
||||||
# addition to RW/RW+ is described in doc/3-faq-tips-etc.mkd, in the section on
|
# in doc/4-wildcard-repositories.mkd. The C and D *suffixes* to the RW/RW+
|
||||||
# "separating delete and rewind rights".
|
# permissions pertain to creating or deleting a BRANCH, and are described in
|
||||||
|
# doc/3-faq-tips-etc.mkd, in the sections on "separating push and create
|
||||||
|
# rights" and "separating delete and rewind rights" respectively.
|
||||||
|
|
||||||
# how permissions are matched:
|
# how permissions are matched:
|
||||||
# - user, repo, and access (W or +) are known. For that combination, if
|
# - user, repo, and access (W or +) are known. For that combination, if
|
||||||
|
|
|
@ -18,6 +18,7 @@ In this document:
|
||||||
* <a href="#better_logging">better logging</a>
|
* <a href="#better_logging">better logging</a>
|
||||||
* <a href="#exclude_or_deny_rules">"exclude" (or "deny") rules</a>
|
* <a href="#exclude_or_deny_rules">"exclude" (or "deny") rules</a>
|
||||||
* <a href="#separating_delete_and_rewind_rights">separating delete and rewind rights</a>
|
* <a href="#separating_delete_and_rewind_rights">separating delete and rewind rights</a>
|
||||||
|
* <a href="#separating_create_and_push_rights">separating create and push rights</a>
|
||||||
* <a href="#file_dir_NAME_based_restrictions">file/dir NAME based restrictions</a>
|
* <a href="#file_dir_NAME_based_restrictions">file/dir NAME based restrictions</a>
|
||||||
* <a href="#delegating_parts_of_the_config_file">delegating parts of the config file</a>
|
* <a href="#delegating_parts_of_the_config_file">delegating parts of the config file</a>
|
||||||
* <a href="#convenience_features">convenience features</a>
|
* <a href="#convenience_features">convenience features</a>
|
||||||
|
@ -381,8 +382,29 @@ Note 2: a quick way to make this the default for *all* your repos is:
|
||||||
where foo can be either the administrator, or if you can ignore the warning
|
where foo can be either the administrator, or if you can ignore the warning
|
||||||
message when you push, a non-existant user.
|
message when you push, a non-existant user.
|
||||||
|
|
||||||
|
Note 3: you can combine this with the "create a branch" permissions described
|
||||||
|
in the next section, as the example line in conf/example.conf shows.
|
||||||
|
|
||||||
[sdrr]: http://groups.google.com/group/gitolite/browse_thread/thread/9f2b4358ce406d4c#
|
[sdrr]: http://groups.google.com/group/gitolite/browse_thread/thread/9f2b4358ce406d4c#
|
||||||
|
|
||||||
|
<a name="separating_create_and_push_rights"></a>
|
||||||
|
|
||||||
|
##### separating create and push rights
|
||||||
|
|
||||||
|
This feature is similar in spirit to the previous one, so please read that
|
||||||
|
section for a general understanding.
|
||||||
|
|
||||||
|
Briefly:
|
||||||
|
|
||||||
|
* branch creation is permitted by using `RWC` or `RW+C` -- essentially the
|
||||||
|
current branch permissions with a `C` suffixed
|
||||||
|
* if a repo has a rule containing such a `C`, then the `RW` and `RW+`
|
||||||
|
permissions (for that repo) no longer permit creation of the ref matched;
|
||||||
|
they will only allow pushing to an existing ref
|
||||||
|
|
||||||
|
Note: you can combine this with the "delete a branch" permissions described in
|
||||||
|
the previous section, as the example line in conf/example.conf shows.
|
||||||
|
|
||||||
<a name="file_dir_NAME_based_restrictions"></a>
|
<a name="file_dir_NAME_based_restrictions"></a>
|
||||||
|
|
||||||
##### file/dir NAME based restrictions
|
##### file/dir NAME based restrictions
|
||||||
|
|
|
@ -67,6 +67,8 @@ $att_acc = '+' if $oldsha ne $merge_base;
|
||||||
# were any 'D' perms specified? If they were, it means we have to separate
|
# were any 'D' perms specified? If they were, it means we have to separate
|
||||||
# deletes from rewinds, so if the new sha is all 0's, change the '+' to a 'D'
|
# deletes from rewinds, so if the new sha is all 0's, change the '+' to a 'D'
|
||||||
$att_acc = 'D' if ( $repos{$ENV{GL_REPO}}{DELETE_IS_D} or $repos{'@all'}{DELETE_IS_D} ) and $newsha eq '0' x 40;
|
$att_acc = 'D' if ( $repos{$ENV{GL_REPO}}{DELETE_IS_D} or $repos{'@all'}{DELETE_IS_D} ) and $newsha eq '0' x 40;
|
||||||
|
# similarly C for create a branch
|
||||||
|
$att_acc = 'C' if ( $repos{$ENV{GL_REPO}}{CREATE_IS_C} or $repos{'@all'}{CREATE_IS_C} ) and $oldsha eq '0' x 40;
|
||||||
|
|
||||||
my @allowed_refs;
|
my @allowed_refs;
|
||||||
# @all repos: see comments in similar code in check_access
|
# @all repos: see comments in similar code in check_access
|
||||||
|
|
|
@ -291,6 +291,7 @@ sub parse_acl
|
||||||
for my $r ('@all', @repo_plus) {
|
for my $r ('@all', @repo_plus) {
|
||||||
my $dr = $repo; $dr = '@all' if $r eq '@all';
|
my $dr = $repo; $dr = '@all' if $r eq '@all';
|
||||||
$repos{$dr}{DELETE_IS_D} = 1 if $repos{$r}{DELETE_IS_D};
|
$repos{$dr}{DELETE_IS_D} = 1 if $repos{$r}{DELETE_IS_D};
|
||||||
|
$repos{$dr}{CREATE_IS_C} = 1 if $repos{$r}{CREATE_IS_C};
|
||||||
$repos{$dr}{NAME_LIMITS} = 1 if $repos{$r}{NAME_LIMITS};
|
$repos{$dr}{NAME_LIMITS} = 1 if $repos{$r}{NAME_LIMITS};
|
||||||
|
|
||||||
for my $u ('@all', "$gl_user - wild", @user_plus) {
|
for my $u ('@all', "$gl_user - wild", @user_plus) {
|
||||||
|
|
|
@ -204,7 +204,7 @@ sub parse_conf_file
|
||||||
s/\bCREAT[EO]R\b/\$creator/g for @repos;
|
s/\bCREAT[EO]R\b/\$creator/g for @repos;
|
||||||
}
|
}
|
||||||
# actual permission line
|
# actual permission line
|
||||||
elsif (/^(-|C|R|RW\+?D?) (.* )?= (.+)/)
|
elsif (/^(-|C|R|RW\+?(?:C?D?|D?C?)) (.* )?= (.+)/)
|
||||||
{
|
{
|
||||||
my $perms = $1;
|
my $perms = $1;
|
||||||
my @refs; @refs = split(' ', $2) if $2;
|
my @refs; @refs = split(' ', $2) if $2;
|
||||||
|
@ -286,6 +286,7 @@ sub parse_conf_file
|
||||||
# that fact easy to find; this changes the meaning of RW+
|
# that fact easy to find; this changes the meaning of RW+
|
||||||
# to no longer permit deletes (see update hook)
|
# to no longer permit deletes (see update hook)
|
||||||
$repos{$repo}{DELETE_IS_D} = 1 if $perms =~ /D/;
|
$repos{$repo}{DELETE_IS_D} = 1 if $perms =~ /D/;
|
||||||
|
$repos{$repo}{CREATE_IS_C} = 1 if $perms =~ /RW.*C/;
|
||||||
|
|
||||||
# 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)
|
||||||
|
|
|
@ -1,23 +1,23 @@
|
||||||
# vim: syn=sh:
|
# vim: syn=sh:
|
||||||
for wr in 0 1
|
|
||||||
do
|
|
||||||
for bc in 0 1
|
for bc in 0 1
|
||||||
do
|
do
|
||||||
cd $TESTDIR
|
cd $TESTDIR
|
||||||
$TESTDIR/rollback
|
$TESTDIR/rollback
|
||||||
editrc GL_WILDREPOS $wr
|
|
||||||
editrc GL_BIG_CONFIG $bc
|
editrc GL_BIG_CONFIG $bc
|
||||||
|
|
||||||
# ----------
|
# ----------
|
||||||
|
|
||||||
|
# test "C" permissions
|
||||||
|
|
||||||
name "INTERNAL"
|
name "INTERNAL"
|
||||||
echo "
|
echo "
|
||||||
@leads = u1 u2
|
@leads = u1 u2
|
||||||
@devs = u1 u2 u3 u4
|
@devs = u1 u2 u3 u4
|
||||||
|
|
||||||
repo foo
|
repo foo
|
||||||
RW+ = @leads
|
RW+C = @leads
|
||||||
- CREATE_REF = @devs
|
RW+C personal/USER/ = @devs
|
||||||
RW+ = @devs
|
RW = @devs
|
||||||
" | ugc
|
" | ugc
|
||||||
|
|
||||||
cd ~/td
|
cd ~/td
|
||||||
|
@ -26,26 +26,80 @@ do
|
||||||
cd foo
|
cd foo
|
||||||
mdc; mdc; mdc; mdc; mdc
|
mdc; mdc; mdc; mdc; mdc
|
||||||
|
|
||||||
name "u1 can push master"
|
name "u1 can push/rewind master on foo"
|
||||||
runlocal git push origin master
|
runlocal git push origin master
|
||||||
expect_push_ok "master -> master"
|
expect_push_ok "master -> master"
|
||||||
|
runlocal git push -f origin master^^:master
|
||||||
|
expect_push_ok "master^^ -> master"
|
||||||
|
|
||||||
name "u2 can create newbr1"
|
name "u2 can create newbr1 on foo"
|
||||||
runlocal git push u2:foo master:newbr1
|
runlocal git push u2:foo master:newbr1
|
||||||
expect_push_ok "master -> newbr1"
|
expect_push_ok "master -> newbr1"
|
||||||
|
|
||||||
name "u3 can push newbr1"
|
name "u3 can push newbr1 on foo"
|
||||||
mdc; mdc; mdc; mdc; mdc
|
mdc; mdc; mdc; mdc; mdc
|
||||||
runlocal git push u3:foo master:newbr1
|
runlocal git push u3:foo master:newbr1
|
||||||
expect_push_ok "master -> newbr1"
|
expect_push_ok "master -> newbr1"
|
||||||
|
|
||||||
name "u4 canNOT push newbr3"
|
name "u4 canNOT create newbr2 on foo"
|
||||||
mdc; mdc; mdc; mdc; mdc
|
mdc; mdc; mdc; mdc; mdc
|
||||||
runlocal git push u3:foo master:newbr3
|
runlocal git push u3:foo master:newbr2
|
||||||
expect "remote: W refs/heads/CREATE_REF u3 DENIED by refs/heads/CREATE_REF"
|
expect "remote: C refs/heads/newbr2 foo u3 DENIED by fallthru"
|
||||||
expect "\[remote rejected\] master -> newbr3 (hook declined)"
|
expect "hook declined"
|
||||||
expect "failed to push"
|
expect "failed to push"
|
||||||
|
|
||||||
|
name "u4 can create/rewind personal/u4/newbr3 on foo"
|
||||||
|
mdc; mdc; mdc; mdc; mdc
|
||||||
|
runlocal git push u4:foo master:personal/u4/newbr3
|
||||||
|
expect_push_ok "master -> personal/u4/newbr3"
|
||||||
|
runlocal git push -f origin master^^:personal/u4/newbr3
|
||||||
|
expect_push_ok "master^^ -> personal/u4/newbr3"
|
||||||
|
|
||||||
|
# bar, without "C" permissions, should behave like old
|
||||||
|
|
||||||
|
name "INTERNAL"
|
||||||
|
echo "
|
||||||
|
@leads = u1 u2
|
||||||
|
@devs = u1 u2 u3 u4
|
||||||
|
|
||||||
|
repo bar
|
||||||
|
RW+ = @leads
|
||||||
|
RW+ personal/USER/ = @devs
|
||||||
|
RW = @devs
|
||||||
|
" | ugc
|
||||||
|
|
||||||
|
cd ~/td
|
||||||
|
runlocal git clone u1:bar
|
||||||
|
|
||||||
|
cd bar
|
||||||
|
mdc; mdc; mdc; mdc; mdc
|
||||||
|
|
||||||
|
name "u1 can push/rewind master on bar"
|
||||||
|
runlocal git push origin master
|
||||||
|
expect_push_ok "master -> master"
|
||||||
|
runlocal git push -f origin master^^:master
|
||||||
|
expect_push_ok "master^^ -> master"
|
||||||
|
|
||||||
|
name "u2 can create newbr1 on bar"
|
||||||
|
runlocal git push u2:bar master:newbr1
|
||||||
|
expect_push_ok "master -> newbr1"
|
||||||
|
|
||||||
|
name "u3 can push newbr1 on bar"
|
||||||
|
mdc; mdc; mdc; mdc; mdc
|
||||||
|
runlocal git push u3:bar master:newbr1
|
||||||
|
expect_push_ok "master -> newbr1"
|
||||||
|
|
||||||
|
name "u4 can create newbr2 on bar"
|
||||||
|
mdc; mdc; mdc; mdc; mdc
|
||||||
|
runlocal git push u3:bar master:newbr2
|
||||||
|
expect_push_ok "master -> newbr2"
|
||||||
|
|
||||||
|
name "u4 can create/rewind personal/u4/newbr3 on bar"
|
||||||
|
mdc; mdc; mdc; mdc; mdc
|
||||||
|
runlocal git push u4:bar master:personal/u4/newbr3
|
||||||
|
expect_push_ok "master -> personal/u4/newbr3"
|
||||||
|
runlocal git push -f origin master^^:personal/u4/newbr3
|
||||||
|
expect_push_ok "master^^ -> personal/u4/newbr3"
|
||||||
|
|
||||||
name INTERNAL
|
name INTERNAL
|
||||||
done
|
done
|
||||||
done
|
|
||||||
|
|
Loading…
Reference in a new issue