File Coverage

blib/lib/App/GitHooks/Plugin/PgBouncerAuthSyntax.pm
Criterion Covered Total %
statement 54 54 100.0
branch 15 20 75.0
condition 5 9 55.5
subroutine 9 9 100.0
pod 3 3 100.0
total 86 95 90.5


line stmt bran cond sub pod time code
1             package App::GitHooks::Plugin::PgBouncerAuthSyntax;
2              
3 22     22   7964240 use strict;
  22         57  
  22         982  
4 22     22   127 use warnings;
  22         46  
  22         629  
5              
6 22     22   122 use base 'App::GitHooks::Plugin';
  22         48  
  22         2982  
7              
8             # External dependencies.
9 22     22   603 use Carp;
  22         96  
  22         1270  
10 22     22   1278 use File::Slurp qw();
  22         22858  
  22         602  
11              
12             # Internal dependencies.
13 22     22   1076 use App::GitHooks::Constants qw( :PLUGIN_RETURN_CODES );
  22         356  
  22         17760  
14              
15              
16             =head1 NAME
17              
18             App::GitHooks::Plugin::PgBouncerAuthSyntax - Verify that the syntax of PgBouncer auth files is correct.
19              
20              
21             =head1 DESCRIPTION
22              
23             This plugin verifies that staged PgBouncer authentication files have a proper
24             syntax before allowing the commit to be completed.
25              
26             See http://pgbouncer.projects.pgfoundry.org/doc/config.html, under the
27             "Authentication File Format" section, for more information about the required
28             syntax.
29              
30              
31             =head1 VERSION
32              
33             Version 1.0.3
34              
35             =cut
36              
37             our $VERSION = '1.0.3';
38              
39              
40             =head1 CONFIGURATION OPTIONS
41              
42             This plugin supports the following options in the C<[PgBouncerAuthSyntax]>
43             section of your C<.githooksrc> file.
44              
45             [PgBouncerAuthSyntax]
46             file_pattern = /^configs\/pgbouncer\/userlist.txt$/
47             comments_setting = disallow
48              
49              
50             =head2 file_pattern
51              
52             A regular expression that will be checked against the path of files that are
53             committed and that indicates a PgBouncer auth file to analyze when it matches.
54              
55             file_pattern = /^configs\/pgbouncer\/userlist.txt$/
56              
57              
58             =head2 comments_setting
59              
60             As of version 1.5.4, PgBouncer does not allow comments. This will however
61             change in the next release, thanks to
62             L.
63              
64             Configure this setting accordingly based on your PgBouncer version:
65              
66             =over 4
67              
68             =item * I
69              
70             Allow comments anywhere. Use with PgBouncer versions above 1.5.4 (not
71             included).
72              
73             comments_setting = allow_anywhere
74              
75             =item * I
76              
77             Allow comments at the end of the file only. PgBouncer will stop parsing the
78             auth file as soon as it encounters an incorrectly formatted line, so you can
79             technically add comments at the end of the file. This setting will prevent you
80             from accidentally adding anything but comments once the first comment is seen,
81             to catch errors that are otherwise tricky to debug.
82              
83             comments_setting = allow_end_only
84              
85             =item * I
86              
87             Don't allow comments at all. The safest setting for PgBouncer versions up to
88             1.5.4 (included).
89              
90             comments_setting = disallow
91              
92             =back
93              
94              
95             =head1 METHODS
96              
97             =head2 get_file_pattern()
98              
99             Return a pattern to filter the files this plugin should analyze.
100              
101             my $file_pattern = App::GitHooks::Plugin::PgBouncerAuthSyntax->get_file_pattern(
102             app => $app,
103             );
104              
105             =cut
106              
107             sub get_file_pattern
108             {
109 21     21 1 4284049 my ( $class, %args ) = @_;
110 21         204 my $app = delete( $args{'app'} );
111 21         232 my $config = $app->get_config();
112              
113             # Retrieve the config value.
114 21         271 my $regex = $config->get_regex( 'PgBouncerAuthSyntax', 'file_pattern' );
115 21 50       1862 croak "'file_pattern' is not defined in the [PgBouncerAuthSyntax] section of your config file"
116             if !defined $regex;
117              
118 21         717 return qr/$regex/;
119             }
120              
121              
122             =head2 get_file_check_description()
123              
124             Return a description of the check performed on files by the plugin and that
125             will be displayed to the user, if applicable, along with an indication of the
126             success or failure of the plugin.
127              
128             my $description = App::GitHooks::Plugin::PgBouncerAuthSyntax->get_file_check_description();
129              
130             =cut
131              
132             sub get_file_check_description
133             {
134 20     20 1 24030 return 'The PgBouncer syntax is correct';
135             }
136              
137              
138             =head2 run_pre_commit_file()
139              
140             Code to execute for each file as part of the pre-commit hook.
141              
142             my $success = App::GitHooks::Plugin::PgBouncerAuthSyntax->run_pre_commit_file();
143              
144             =cut
145              
146             sub run_pre_commit_file
147             {
148 10     10 1 30750 my ( $class, %args ) = @_;
149 10         436 my $file = delete( $args{'file'} );
150 10         211 my $git_action = delete( $args{'git_action'} );
151 10         111 my $app = delete( $args{'app'} );
152 10         649 my $repository = $app->get_repository();
153 10         468 my $config = $app->get_config();
154              
155             # Ignore deleted files.
156 10 50       324 return $PLUGIN_RETURN_SKIPPED
157             if $git_action eq 'D';
158              
159             # Determine which setting to use for comments.
160 10         545 my $comments_setting = $config->get( 'PgBouncerAuthSyntax', 'comments_setting' );
161 10 50 33     933 croak '"comments_setting" needs to be defined in the [PgBouncerAuthSyntax] section of your .githooksrc file'
162             if !defined( $comments_setting ) || ( $comments_setting eq '' );
163 10 50       761 croak 'The value of "comments_setting" in the [PgBouncerAuthSyntax] section of your .githooksrc file is not valid'
164             if $comments_setting !~ /^(?:allow_anywhere|allow_end_only|disallow)$/x;
165              
166             # Retrieve lines.
167 10         589 my @lines = File::Slurp::read_file( $repository->work_tree() . '/' . $file );
168              
169             # Find the incorrectly formatted lines.
170 10         11766 my @issues = ();
171 10         49 my $comments_detected = 0;
172 10         128 for ( my $i = 0; $i < scalar( @lines ); $i++ )
173             {
174 21         86 my $line = $lines[ $i ];
175              
176             # Skip blank lines.
177             next
178 21 50 33     375 if !defined( $line ) || ( $line eq '' );
179              
180             # Handle comments.
181 21 100       131 if ( substr( $line, 0, 1 ) eq ';' )
182             {
183 5         19 $comments_detected = 1;
184              
185             # If we don't allow comments, note the error before moving on to the next
186             # line.
187 5 100       30 if ( $comments_setting eq 'disallow' )
188             {
189 2         50 push(
190             @issues,
191             {
192             line_number => $i,
193             line => $line,
194             }
195             );
196             }
197              
198 5         27 next;
199             }
200 16 100 100     389 if ( $comments_detected && ( $comments_setting eq 'allow_end_only' ) )
201             {
202             # This line is not a comment, but comment lines have already been seen
203             # and we only allow comments at the end of the file.
204 1         27 push(
205             @issues,
206             {
207             line_number => $i,
208             line => $line,
209             }
210             );
211 1         7 next;
212             }
213              
214             # Skip lines with the correct username/password specification.
215             next
216 15 100       484 if $line =~ /
217             ^
218             "[^"]*" # Username.
219             \ # Space.
220             "[^"]*" # Password.
221             (?:\ .*)? # Remainder of the line, no specific format required except
222             # for a space if anything follows.
223             $
224             /x;
225              
226 3         436 push(
227             @issues,
228             {
229             line_number => $i,
230             line => $line,
231             }
232             );
233             }
234              
235 10 100       146 die "Incorrectly formatted lines:\n" . join( '', map { "Line $_->{'line_number'}: $_->{'line'}" } @issues ) . "\n"
  6         291  
236             if scalar( @issues ) != 0;
237              
238 4         43 return $PLUGIN_RETURN_PASSED;
239             }
240              
241              
242             =head1 BUGS
243              
244             Please report any bugs or feature requests through the web interface at
245             L.
246             I will be notified, and then you'll automatically be notified of progress on
247             your bug as I make changes.
248              
249              
250             =head1 SUPPORT
251              
252             You can find documentation for this module with the perldoc command.
253              
254             perldoc App::GitHooks::Plugin::PgBouncerAuthSyntax
255              
256              
257             You can also look for information at:
258              
259             =over
260              
261             =item * GitHub's request tracker
262              
263             L
264              
265             =item * AnnoCPAN: Annotated CPAN documentation
266              
267             L
268              
269             =item * CPAN Ratings
270              
271             L
272              
273             =item * MetaCPAN
274              
275             L
276              
277             =back
278              
279              
280             =head1 AUTHOR
281              
282             L,
283             C<< >>.
284              
285              
286             =head1 COPYRIGHT & LICENSE
287              
288             Copyright 2013-2014 Guillaume Aubert.
289              
290             This program is free software: you can redistribute it and/or modify it under
291             the terms of the GNU General Public License version 3 as published by the Free
292             Software Foundation.
293              
294             This program is distributed in the hope that it will be useful, but WITHOUT ANY
295             WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
296             PARTICULAR PURPOSE. See the GNU General Public License for more details.
297              
298             You should have received a copy of the GNU General Public License along with
299             this program. If not, see http://www.gnu.org/licenses/
300              
301             =cut
302              
303             1;