summaryrefslogtreecommitdiffstats
path: root/src/triggers/expand-deny-messages
blob: 107202c0dbf113360ad0bd2eb9ca7c2fdf68921a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
#!/usr/bin/perl
use strict;
use warnings;

$|++;

# program name: expand-deny-messages

# DOCUMENTATION IS AT THE BOTTOM OF THIS FILE; PLEASE READ

use lib $ENV{GL_LIBDIR};
use Gitolite::Rc;
use Gitolite::Common;

my %attempted_access = (
    # see triggers.html
    'ACCESS_1' => {
        'R' => 'Repo read',
        'W' => 'Repo write',
    },
    'ACCESS_2' => {
        'W' => "Fast forward push",
        '+' => "Rewind push branch or overwrite tag",
        'C' => "Create ref",
        'D' => "Delete ref",
    }
);

# env var to disable is set?
exit 0 if $ENV{GL_OPTION_EDM_DISABLE};

# argument 1
my $a12 = shift;    # ACCESS_1 or ACCESS_2
exit 0 if $a12 !~ /^ACCESS_[12]$/;    # shouldn't happen; error in rc file?

# the rest of the arguments
my ( $repo, $user, $aa, $ref, $msg, $oldsha, $newsha ) = @ARGV;

# we're only interested in deny messages
exit 0 if $msg !~ /DENIED/;

print STDERR "\nFATAL -- ACCESS DENIED\n";

_info( "Repo",      $repo );
_info( "User",      $user );
_info( "Stage",     ( $a12 eq 'ACCESS_1' ? "Before git was called" : "From git's update hook" ) );
_info( "Ref",       _ref($ref) ) if $a12 eq 'ACCESS_2';
_info( "Operation", _op( $a12, $aa, $oldsha, $newsha ) );

if ( $ref =~ m((^VREF/[^/]+)) ) {
    my $vref      = $1;
    if ($ref =~ s(^VREF/NAME/)()) {
        print STDERR "You're apparently not allowed to push '$ref'";
    } else {
        my $vref_text = slurp( _which( $vref, 'x' ) );
        my $etag      = '(?:help|explain|explanation)';
        $vref_text =~ m(^\s*# $etag.start\n(.*)^\s*# $etag.end\n)sm
          and print STDERR "Explanation for $vref:\n$1";
  }
}

print STDERR "\n";
print STDERR "$ENV{GL_OPTION_EDM_EXTRA_INFO}\n\n" if $ENV{GL_OPTION_EDM_EXTRA_INFO};

# ------------------------------------------------------------------------

sub _ref {
    my $r = shift;
    return "VREF '$r'"   if $r =~ s(^VREF/)();
    return "Branch '$r'" if $r =~ s(^refs/heads/)();
    return "Tag '$r'"    if $r =~ s(^refs/tags/)();
    return "Non-standard ref '$r'";
}

sub _info {
    printf STDERR "%-14s  %-60s\n", @_;
}

sub _op {
    my ( $a12, $aa, $oldsha, $newsha ) = @_;

    # first remove the M part and save the text for later addition if needed
    my $merge = ( $aa =~ s/M// ? " with merge commit" : "" );

    # next, the attempted access is modified to reflect the actual operation being
    # attempted.  NOTE: this no longer necessarily reflects what the gitolite log
    # file stores; it's more granular and truly distinguishes a branch create from
    # an ff push, etc.  Could help when user typos a branch name I suppose
    $aa = 'C' if $oldsha and $oldsha eq '0' x 40;
    $aa = 'D' if $newsha and $newsha eq '0' x 40;

    # then we map it, add merge text if any
    my $op = $attempted_access{$a12}{$aa} || "Unknown operation '$aa'";
    $op .= $merge;

    return $op;
}

__END__

ENABLING THE FEATURE
--------------------

To enable this feature, uncomment the line in the rc file if your gitolite was
installed recently enough.  Otherwise you will need to add these lines to the
end of your rc file, just before the "%RC" block ends:

    ACCESS_1 => [
        'expand-deny-messages',
    ],

    ACCESS_2 => [
        'expand-deny-messages',
    ],

Please don't miss the trailing commas!

DISABLING IT FOR SPECIFIC REPOS
-------------------------------

Once it is enabled at the rc file level, if you wish to disable it for
specific repositories just add a line like this to those repos:

        option ENV.EDM_DISABLE = 1

Or you can also disable it for all repos, then enable it for some:

    repo @all
        option ENV.EDM_DISABLE = 1

    # ... then later ...

    repo foo bar @baz
        option ENV.EDM_DISABLE = 0

(options.html[1] and pages linked from it will explain how that works).

[1]: http://gitolite.com/gitolite/options.html

SUPPLYING EXTRA INFORMATION
---------------------------

You can also supply some extra information to be printed, by adding a line
like this to each repository in the gitolite.conf file:

        option ENV.EDM_EXTRA_INFO = "please contact alice@example.com"

You could of course add it under a "repo @all" section if you like.

SUPPLYING EXTRA INFORMATION FOR VREFs
-------------------------------------

If you have VREFs that do funky things and you want to **lecture** your users
when they screw up, add something like the following to your VREF code.

    # help start

    Some help text.

    Some more help text.  This can be
    multi-line.

    (etc etc etc)

    # help end

Then everything between the "# help start" line and the "# help end" line will
get printed if a users falls afoul of this VREF.  If any of the lines shown
are not valid syntax for your language, figure out some way to put the whole
thing in a comment block.  Here a C example:

    /*
    # help start
    line 1
    line 2
    ...
    last line
    # help end
    */

Even if your language does not support multi-line comments like C does, there
may be other ways to specify those lines.  Here's an example in shell:

    cat << EOF > /dev/null
    # help start
    line 1
    line 2
    ...
    last line
    # help end
    EOF