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   5103651 use strict;
  22         43  
  22         666  
4 22     22   90 use warnings;
  22         34  
  22         610  
5              
6 22     22   91 use base 'App::GitHooks::Plugin';
  22         34  
  22         2093  
7              
8             # External dependencies.
9 22     22   373 use Carp;
  22         30  
  22         1146  
10 22     22   11497 use File::Slurp qw();
  22         84259  
  22         582  
11              
12             # Internal dependencies.
13 22     22   613 use App::GitHooks::Constants qw( :PLUGIN_RETURN_CODES );
  22         3568  
  22         13812  
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.1.0
34              
35             =cut
36              
37             our $VERSION = '1.1.0';
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 1468285 my ( $class, %args ) = @_;
110 21         189 my $app = delete( $args{'app'} );
111 21         161 my $config = $app->get_config();
112              
113             # Retrieve the config value.
114 21         449 my $regex = $config->get_regex( 'PgBouncerAuthSyntax', 'file_pattern' );
115 21 50       761 croak "'file_pattern' is not defined in the [PgBouncerAuthSyntax] section of your config file"
116             if !defined $regex;
117              
118 21         456 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 19478 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 19681 my ( $class, %args ) = @_;
149 10         296 my $file = delete( $args{'file'} );
150 10         84 my $git_action = delete( $args{'git_action'} );
151 10         78 my $app = delete( $args{'app'} );
152 10         1062 my $repository = $app->get_repository();
153 10         316 my $config = $app->get_config();
154              
155             # Ignore deleted files.
156 10 50       854 return $PLUGIN_RETURN_SKIPPED
157             if $git_action eq 'D';
158              
159             # Determine which setting to use for comments.
160 10         94 my $comments_setting = $config->get( 'PgBouncerAuthSyntax', 'comments_setting' );
161 10 50 33     644 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       535 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         279 my @lines = File::Slurp::read_file( $repository->work_tree() . '/' . $file );
168              
169             # Find the incorrectly formatted lines.
170 10         5386 my @issues = ();
171 10         31 my $comments_detected = 0;
172 10         93 for ( my $i = 0; $i < scalar( @lines ); $i++ )
173             {
174 21         49 my $line = $lines[ $i ];
175              
176             # Skip blank lines.
177             next
178 21 50 33     299 if !defined( $line ) || ( $line eq '' );
179              
180             # Handle comments.
181 21 100       92 if ( substr( $line, 0, 1 ) eq ';' )
182             {
183 5         7 $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       26 if ( $comments_setting eq 'disallow' )
188             {
189 2         26 push(
190             @issues,
191             {
192             line_number => $i,
193             line => $line,
194             }
195             );
196             }
197              
198 5         15 next;
199             }
200 16 100 100     112 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         18 push(
205             @issues,
206             {
207             line_number => $i,
208             line => $line,
209             }
210             );
211 1         6 next;
212             }
213              
214             # Skip lines with the correct username/password specification.
215             next
216 15 100       250 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         42 push(
227             @issues,
228             {
229             line_number => $i,
230             line => $line,
231             }
232             );
233             }
234              
235 10 100       102 die "Incorrectly formatted lines:\n" . join( '', map { "Line $_->{'line_number'}: $_->{'line'}" } @issues ) . "\n"
  6         224  
236             if scalar( @issues ) != 0;
237              
238 4         32 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-2017 Guillaume Aubert.
289              
290             This code is free software; you can redistribute it and/or modify it under the
291             same terms as Perl 5 itself.
292              
293             This program is distributed in the hope that it will be useful, but WITHOUT ANY
294             WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
295             PARTICULAR PURPOSE. See the LICENSE file for more details.
296              
297             =cut
298              
299             1;