File Coverage

blib/lib/Perl/Critic/Policy/Perlsecret.pm
Criterion Covered Total %
statement 103 103 100.0
branch 80 90 88.8
condition 41 54 75.9
subroutine 32 32 100.0
pod 4 6 66.6
total 260 285 91.2


line stmt bran cond sub pod time code
1             package Perl::Critic::Policy::Perlsecret;
2             # ABSTRACT: Prevent perlsecrets entering your codebase
3              
4 4     4   279304 use 5.006001;
  4         13  
5 4     4   18 use strict;
  4         5  
  4         78  
6 4     4   13 use warnings;
  4         9  
  4         110  
7              
8 4     4   1629 use parent 'Perl::Critic::Policy';
  4         814  
  4         21  
9              
10 4     4   508661 use Carp;
  4         7  
  4         234  
11 4     4   20 use Perl::Critic::Utils;
  4         7  
  4         53  
12 4     4   2849 use List::Util 'first';
  4         6  
  4         7717  
13              
14             our $VERSION = '0.0.9';
15              
16             Readonly::Scalar my $DESCRIPTION => 'Perlsecret risk.';
17             Readonly::Scalar my $EXPLANATION => 'Perlsecret detected.';
18              
19             # Eskimo Greeting skipped as only used in one liners
20             Readonly::Hash my %default_violations => (
21             'Venus' => \&_venus,
22             'Baby Cart' => \&_baby_cart,
23             'Bang Bang' => \&_bang_bang,
24             'Inchworm' => \&_inchworm,
25             'Inchworm on a Stick' => \&_inchworm_on_a_stick,
26             'Space Station' => \&_space_station,
27             'Goatse' => \&_goatse,
28             'Flaming X-Wing' => \&_flaming_x_wing,
29             'Kite' => \&_kite,
30             'Ornate Double Edged Sword' => \&_ornate_double_edged_sword,
31             'Flathead' => \&_flathead,
32             'Phillips' => \&_phillips,
33             'Torx' => \&_torx,
34             'Pozidriv' => \&_pozidriv,
35             'Winking Fat Comma' => \&_winking_fat_comma,
36             'Enterprise' => \&_enterprise,
37             'Key of Truth' => \&_key_of_truth,
38             'Abbott and Costello' => \&_abbott_and_costello,
39             );
40              
41             sub default_severity {
42 38     38 1 466 return $Perl::Critic::Utils::SEVERITY_HIGHEST;
43             }
44              
45             sub default_themes {
46 1     1 1 127766 return qw( perlsecret );
47             }
48              
49             sub applies_to {
50 23     23 1 172845 return qw(
51             PPI::Statement
52             );
53             }
54              
55             sub supported_parameters {
56             return (
57             {
58 25     25 0 1075426 name => 'allow_secrets',
59             description => q<A list of perlsecrets to allow.>,
60             default_string => '',
61             },
62              
63             {
64             name => 'disallow_secrets',
65             description => q<A list of perlsecrets to disallow (default: all perlsecrets).>,
66             default_string =>
67             'Venus, Baby Cart, Bang Bang, Inchworm, Inchworm on a Stick, ' .
68             'Space Station, Goatse, Flaming X-Wing, Kite, ' .
69             'Ornate Double Edged Sword, Flathead, Phillips, Torx, ' .
70             'Pozidriv, Winking Fat Comma, Enterprise, Key of Truth, ' .
71             'Abbott and Costello',
72             },
73             );
74             }
75              
76             my $SPLIT_RE = qr/\s*,\s*/;
77              
78             sub read_config_list {
79 176     176 0 211 my ( $self, $str ) = @_;
80              
81             my @values = map {
82 176         2150 ( my $new = $_ ) =~ s/^\s+|\s+$//;
  1462         3852  
83 1462         1857 $new;
84             } split $SPLIT_RE, $str;
85              
86 176         720 return @values;
87             }
88              
89             sub violates {
90 88     88 1 6255 my ( $self, $element, $doc ) = @_;
91              
92             my @disallowed = $self->read_config_list(
93 88         239 $self->{'_disallow_secrets'}
94             );
95              
96             @disallowed
97 88 50       279 or @disallowed = keys %default_violations;
98              
99             my @allowed = $self->read_config_list(
100 88         220 $self->{'_allow_secrets'}
101             );
102              
103 88         93 my %violations;
104 88         153 foreach my $secret (@disallowed) {
105 1455 100       7823 if ( ! exists $default_violations{$secret} ) {
106 1         281 croak("$secret is not a known secret");
107             }
108              
109 14     14   46 first { $secret eq $_ } @allowed
110 1454 100       9795 and next;
111              
112 1447         4226 $violations{$secret} = $default_violations{$secret};
113             }
114              
115 87         629 for my $policy ( keys %violations ) {
116 1099 100       6831 if ( $violations{$policy}->($element) ) {
117 38         2213 return $self->violation( $DESCRIPTION . " $policy ",
118             $EXPLANATION, $element );
119             }
120             }
121              
122 49         405 return; # No matches return i.e. no violations
123             }
124              
125             sub _venus {
126 58     58   120 for my $child ($_[0]->children)
127             {
128 293 100       2263 next unless ref($child) eq 'PPI::Token::Operator';
129              
130 64 100       162 return 1 if $child->previous_sibling eq '0';
131 63 100       1989 return 1 if $child->next_sibling eq '0';
132             }
133             }
134              
135             sub _baby_cart {
136 71     71   178 for my $child ($_[0]->children)
137             {
138 346 100       868 if (ref($child) eq 'PPI::Token::Cast' ) {
139 3 50       14 return 1 if $child->snext_sibling =~ m/\{\s*?\[/;
140             }
141 343 100       719 if (ref($child) eq 'PPI::Token::Quote::Double') {
142 5 100       17 return 1 if $child =~ m/@\{\s*?\[/;
143             };
144              
145             }
146             }
147              
148             sub _bang_bang {
149 64     64   158 for my $child ($_[0]->children)
150             {
151 308 100       1543 next unless ref($child) eq 'PPI::Token::Operator';
152 58 100 100     110 return 1 if $child eq '!' && $child->snext_sibling eq '!';
153             }
154             }
155              
156             sub _inchworm {
157 61     61   130 for my $child ($_[0]->children)
158             {
159 298 100       1258 next unless ref($child) eq 'PPI::Token::Operator';
160 53 100       100 return 1 if $child eq '~~';
161 52 100 66     562 return 1 if $child eq '~' && $child->snext_sibling eq '~';
162             }
163             }
164              
165             sub _inchworm_on_a_stick {
166 63     63   148 for my $child ($_[0]->children)
167             {
168 335 100       1471 next unless ref($child) eq 'PPI::Token::Operator';
169              
170 77 100 100     130 return 1 if $child eq '~' && $child->snext_sibling eq '-';
171 76 100 66     861 return 1 if $child eq '-' && $child->snext_sibling eq '~';
172             }
173             }
174              
175             sub _space_station {
176 62     62   137 for my $child ($_[0]->children)
177             {
178 335 100       1530 next unless ref($child) eq 'PPI::Token::Operator';
179              
180 75 100 100     119 return 1 if $child eq '-'
      66        
181             && $child->snext_sibling eq '+'
182             && $child->snext_sibling->snext_sibling eq '-';
183             }
184             }
185              
186             sub _goatse {
187 59     59   150 for my $child ($_[0]->children)
188             {
189 289 100       1437 next unless ref($child) eq 'PPI::Structure::List';
190 20 100 100     61 return 1 if $child->sprevious_sibling eq '=' && $child->snext_sibling eq '=';
191             }
192             }
193              
194             sub _flaming_x_wing {
195 66     66   184 for my $child ($_[0]->children)
196             {
197              
198 329 100       940 next unless ref($child) eq 'PPI::Token::QuoteLike::Readline';
199 2 50 33     10 return 1 if $child->sprevious_sibling eq '='
200             && $child->snext_sibling eq '=~';
201             }
202             }
203              
204             sub _kite {
205 57     57   128 for my $child ($_[0]->children)
206             {
207 279 100       1228 next unless ref($child) eq 'PPI::Token::Operator';
208 60 100 66     96 return 1 if $child eq '~~'
209             && $child->snext_sibling eq '<>';
210             }
211             }
212              
213             sub _ornate_double_edged_sword {
214 57     57   159 for my $child ($_[0]->children)
215             {
216 282 100       3565 next unless $child eq '<<m';
217 1 50 33     26 return 1 if $child->snext_sibling eq '=~'
218             && $child->snext_sibling->snext_sibling eq 'm>>';
219             }
220             }
221              
222             sub _flathead {
223 57     57   125 for my $child ($_[0]->children)
224             {
225 284 100       3514 next unless $child eq '-=';
226 1 50       11 return 1 if $child->snext_sibling eq '!';
227             }
228             }
229              
230             sub _phillips {
231 64     64   145 for my $child ($_[0]->children)
232             {
233 316 100       3875 next unless $child eq '+=';
234 2 50       23 return 1 if $child->snext_sibling eq '!';
235             }
236             }
237              
238             sub _torx {
239 56     56   111 for my $child ($_[0]->children)
240             {
241 272 100       3259 next unless $child eq '*=';
242 1 50       11 return 1 if $child->snext_sibling eq '!';
243             }
244             }
245              
246             sub _pozidriv {
247 60     60   195 for my $child ($_[0]->children)
248             {
249 293 100       3561 next unless $child eq 'x=';
250 1 50       10 return 1 if $child->snext_sibling eq '!';
251             }
252             }
253              
254             sub _winking_fat_comma {
255 62     62   137 for my $child ($_[0]->children)
256             {
257 308 100 100     1731 next unless ref($child) eq 'PPI::Token::Operator'
258             && $child eq ',';
259 7 100       77 return 1 if $child->snext_sibling eq '=>';
260             }
261             }
262             sub _enterprise {
263 60     60   124 for my $child ($_[0]->children)
264             {
265 292 100       1606 next unless $child->class eq 'PPI::Structure::List';
266 15 50 66     76 return 1 if $child->snext_sibling eq 'x'
      66        
267             && $child->snext_sibling->snext_sibling eq '!'
268             && $child->snext_sibling->snext_sibling->snext_sibling eq '!'
269             }
270             }
271              
272             sub _key_of_truth {
273 61     61   138 for my $child ($_[0]->children)
274             {
275 336 100       1445 next unless $child->class eq 'PPI::Token::Number';
276 7 50 100     30 return 1 if $child eq '0'
      66        
      66        
277             && $child->snext_sibling eq '+'
278             && $child->snext_sibling->snext_sibling eq '!'
279             && $child->snext_sibling->snext_sibling->snext_sibling eq '!'
280             }
281             }
282              
283             sub _abbott_and_costello {
284 61     61   149 for my $child ($_[0]->children)
285             {
286 331 100       2175 next unless ref($child) eq 'PPI::Token::Operator';
287              
288 73 100 100     125 return 1 if ($child eq '||' || $child eq '//')
      66        
289             && $child->snext_sibling->class eq 'PPI::Structure::List';
290             }
291             }
292              
293             1;
294              
295             __END__
296              
297             =pod
298              
299             =encoding UTF-8
300              
301             =head1 NAME
302              
303             Perl::Critic::Policy::Perlsecret - Prevent perlsecrets entering your codebase
304              
305             =head1 VERSION
306              
307             version 0.0.9
308              
309             =head1 SYNOPSIS
310              
311             # in your .perlcriticrc
312             [Perlsecret]
313              
314             # overriding things
315             [Perlsecret]
316             allow_secrets = Bang Bang, Venus
317              
318             =head1 DESCRIPTION
319              
320             This policy checks for L<perlsecret> operators in your code and warns you
321             about them.
322              
323             You can override the secrets that are allowed or disallowed using the
324             parameters C<allow_secrets> and C<disallow_secrets>. The default is to
325             simply disallow everything.
326              
327             Notice the secrets are capitalized correctly ("Ornate Double-Bladed Sword",
328             not "Ornate double-bladed sword").
329              
330             [Perlsecret]
331             disallow_secrets = Flathead, Phillips, Pozidriv, Torx, Enterprise
332              
333             This provides the list to disallow.
334              
335             [Perlsecret]
336             allow_secrets = Bang Bang
337              
338             You can provide both, in which case it will start with the disallow list
339             you provided as the default and then allow everything in the allow list.
340             (There isn't much value to provide both of these.)
341              
342             =head1 NAME
343              
344             Perl::Critic::Policy::Perlsecret - Prevent perlsecrets entering your codebase
345              
346             =head1 VERSION
347              
348             version 0.0.9
349              
350             =head1 AUTHOR
351              
352             Lance Wicks <lancew@cpan.org>
353              
354             =head1 COPYRIGHT AND LICENSE
355              
356             This software is Copyright (c) 2016 by Lance Wicks.
357              
358             This is free software, licensed under:
359              
360             The GNU General Public License, Version 3, June 2007
361              
362             =cut