From 967af2c9938f21f396fcef3b874886dbb7795011 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Tue, 30 Mar 2010 20:01:49 +0530 Subject: [PATCH] compile/update: new "D" permission normally, RW+ means permission to rewind or delete. Now, if you use "D" permission anywhere in a repo config, that means "delete" and RW+ then means only "rewind", no delete. --- conf/example.conf | 14 ++++++-------- doc/3-faq-tips-etc.mkd | 23 +++++++++++++++++++++++ hooks/common/update | 4 ++++ src/gl-compile-conf | 9 +++++++-- 4 files changed, 40 insertions(+), 10 deletions(-) diff --git a/conf/example.conf b/conf/example.conf index 8ba4919..6d8c3d7 100644 --- a/conf/example.conf +++ b/conf/example.conf @@ -60,11 +60,6 @@ # "@interns" now has 3 names in it, but note that this does # not change @staff -# WILDCARD REPOSITORIES ("wildrepos" BRANCH ONLY) -# ----------------------------------------- - -# Please see doc/4-wildcard-repositories.mkd for details - # REPO AND BRANCH PERMISSIONS # --------------------------- @@ -72,10 +67,13 @@ # start line: # repo [one or more repos and/or repo groups] # followed by one or more permissions lines: -# (R|RW|RW+) [zero or more refexes] = [one or more users] +# (C|D|R|RW|RW+) [zero or more refexes] = [one or more users] -# there are 3 types of permissions: R, RW, and RW+. The "+" means permission -# to "rewind" (force push a non-fast forward to) a branch +# there are 5 types of permissions: R, RW, and RW+ are simple (the "+" means +# 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 +# permission is described in doc/3-faq-tips-etc.mkd, in the "advanced +# features" section. # how permissions are matched: # - user, repo, and access (W or +) are known. For that combination, if diff --git a/doc/3-faq-tips-etc.mkd b/doc/3-faq-tips-etc.mkd index 01ae889..982db8f 100644 --- a/doc/3-faq-tips-etc.mkd +++ b/doc/3-faq-tips-etc.mkd @@ -18,6 +18,7 @@ In this document: * two levels of access rights checking * better logging * "exclude" (or "deny") rules + * the "D" permission -- separating delete and rewind rights * file/dir NAME based restrictions * delegating parts of the config file * convenience features @@ -366,6 +367,28 @@ And here's how it works: before the third one, and it has a `-` as the permission, so the push fails +#### the "D" permission -- separating delete and rewind rights + +Since the beginning, `RW+` meant being able to rewind *or* delete a ref. My +stand is that these two are fairly similar, and infact a rewind is almost the +same as a delete+push (the only difference I can see is if you had +core.logAllRefUpdates set, which is *not* a default setting). + +However, there seem to be cases where it is useful to distinguish them -- +situations where one of them should be restricted more than the other. +([Arguments][sdrr] exist for both sides: restrict delete more than rewind, and +vice versa). + +So we now allow these two rights to be separated. Just use the new `D` +permission anywhere in the config for the repo, and instantly all `RW+` +permissions (for that repo) cease to permit deletion of the ref matched. + +This provides the *greatest* backward compatibility (if you don't specify any +`D` permissions, everything works just as before), while also enabling the new +semantics at the granularity of a repo, instead of the entire config. + +[sdrr]: http://groups.google.com/group/gitolite/browse_thread/thread/9f2b4358ce406d4c# + #### file/dir NAME based restrictions In addition to branch-name based restrictions, gitolite also allows you to diff --git a/hooks/common/update b/hooks/common/update index d8f610c..e1b1209 100755 --- a/hooks/common/update +++ b/hooks/common/update @@ -75,6 +75,10 @@ $perm = '+' if $ref =~ m(refs/tags/) and $oldsha ne ('0' x 40); # notice that ref delete looks like a rewind, as it should $perm = '+' if $oldsha ne $merge_base; +# 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' +$perm = 'D' if $repos{$ENV{GL_REPO}}{DELETE_IS_D} and $newsha eq '0' x 40; + my @allowed_refs; # @all repos: see comments in similar code in check_access push @allowed_refs, @ { $repos{$ENV{GL_REPO}}{$ENV{GL_USER}} || [] }; diff --git a/src/gl-compile-conf b/src/gl-compile-conf index ed74722..575ee61 100755 --- a/src/gl-compile-conf +++ b/src/gl-compile-conf @@ -191,7 +191,7 @@ sub parse_conf_file s/\bCREAT[EO]R\b/\$creater/g for @repos; } # actual permission line - elsif (/^(-|C|R|RW|RW\+) (.* )?= (.+)/) + elsif (/^(-|C|D|R|RW|RW\+) (.* )?= (.+)/) { my $perms = $1; my @refs; @refs = split(' ', $2) if $2; @@ -257,7 +257,12 @@ sub parse_conf_file # for 1st level check (see faq/tips doc) $repos{$repo}{C}{$user} = 1, next if $perms eq 'C'; $repos{$repo}{R}{$user} = 1 if $perms =~ /R/; - $repos{$repo}{W}{$user} = 1 if $perms =~ /W/; + $repos{$repo}{W}{$user} = 1 if $perms =~ /W|D/; + + # if the user specified even a single 'D' anywhere, make + # that fact easy to find; this changes the meaning of RW+ + # to no longer permit deletes (see update hook) + $repos{$repo}{DELETE_IS_D} = 1 if $perms eq 'D'; # for 2nd level check, store each "ref, perms" pair in order for my $ref (@refs)