File Coverage

blib/lib/Perl/Critic/Policy/Perlsecret.pm
Criterion Covered Total %
statement 103 103 100.0
branch 80 90 88.8
condition 46 60 76.6
subroutine 32 32 100.0
pod 4 6 66.6
total 265 291 91.0


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   193535 use 5.006001;
  4         11  
5 4     4   15 use strict;
  4         4  
  4         63  
6 4     4   11 use warnings;
  4         9  
  4         91  
7              
8 4     4   1231 use parent 'Perl::Critic::Policy';
  4         824  
  4         18  
9              
10 4     4   408999 use Carp;
  4         6  
  4         211  
11 4     4   16 use Perl::Critic::Utils;
  4         5  
  4         45  
12 4     4   2009 use List::Util 'first';
  4         4  
  4         4758  
13              
14             our $VERSION = '0.0.10';
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 286 return $Perl::Critic::Utils::SEVERITY_HIGHEST;
43             }
44              
45             sub default_themes {
46 1     1 1 97029 return qw( perlsecret );
47             }
48              
49             sub applies_to {
50 23     23 1 139868 return qw(
51             PPI::Statement
52             );
53             }
54              
55             sub supported_parameters {
56             return (
57 25     25 0 914184 { name => 'allow_secrets',
58             description => q<A list of perlsecrets to allow.>,
59             default_string => '',
60             },
61              
62             { name => 'disallow_secrets',
63             description =>
64             q<A list of perlsecrets to disallow (default: all perlsecrets).>,
65             default_string =>
66             'Venus, Baby Cart, Bang Bang, Inchworm, Inchworm on a Stick, '
67             . 'Space Station, Goatse, Flaming X-Wing, Kite, '
68             . 'Ornate Double Edged Sword, Flathead, Phillips, Torx, '
69             . 'Pozidriv, Winking Fat Comma, Enterprise, Key of Truth, '
70             . 'Abbott and Costello',
71             },
72             );
73             }
74              
75             my $SPLIT_RE = qr/\s*,\s*/;
76              
77             sub read_config_list {
78 182     182 0 194 my ( $self, $str ) = @_;
79              
80             my @values = map {
81 182         1671 ( my $new = $_ ) =~ s/^\s+|\s+$//;
  1516         2894  
82 1516         1350 $new;
83             } split $SPLIT_RE, $str;
84              
85 182         526 return @values;
86             }
87              
88             sub violates {
89 91     91 1 5048 my ( $self, $element, $doc ) = @_;
90              
91 91         186 my @disallowed = $self->read_config_list( $self->{'_disallow_secrets'} );
92              
93             @disallowed
94 91 50       234 or @disallowed = keys %default_violations;
95              
96 91         190 my @allowed = $self->read_config_list( $self->{'_allow_secrets'} );
97              
98 91         76 my %violations;
99 91         148 foreach my $secret (@disallowed) {
100 1509 100       5915 if ( !exists $default_violations{$secret} ) {
101 1         187 croak("$secret is not a known secret");
102             }
103              
104 14     14   51 first { $secret eq $_ } @allowed
105 1508 100       7595 and next;
106              
107 1501         3064 $violations{$secret} = $default_violations{$secret};
108             }
109              
110 90         474 for my $policy ( keys %violations ) {
111 1181 100       5155 if ( $violations{$policy}->($element) ) {
112 38         1497 return $self->violation( $DESCRIPTION . " $policy ",
113             $EXPLANATION, $element );
114             }
115             }
116              
117 52         407 return; # No matches return i.e. no violations
118             }
119              
120             sub _venus {
121 63     63   103 for my $child ( $_[0]->children ) {
122 322 100       1770 next unless ref($child) eq 'PPI::Token::Operator';
123              
124 64 100       120 return 1 if $child->previous_sibling eq '0';
125 63 100       1225 return 1 if $child->next_sibling eq '0';
126             }
127             }
128              
129             sub _baby_cart {
130 77     77   158 for my $child ( $_[0]->children ) {
131 423 100       742 if ( ref($child) eq 'PPI::Token::Cast' ) {
132 3 50       11 return 1 if $child->snext_sibling =~ m/\{\s*?\[/;
133             }
134 420 100       703 if ( ref($child) eq 'PPI::Token::Quote::Double' ) {
135 3 100       9 return 1 if $child =~ m/@\{\s*?\[/;
136             }
137              
138             }
139             }
140              
141             sub _bang_bang {
142 69     69   112 for my $child ( $_[0]->children ) {
143 375 100       1259 next unless ref($child) eq 'PPI::Token::Operator';
144 82 100 100     102 return 1 if $child eq '!' && $child->snext_sibling eq '!';
145             }
146             }
147              
148             sub _inchworm {
149 69     69   120 for my $child ( $_[0]->children ) {
150 394 100       1336 next unless ref($child) eq 'PPI::Token::Operator';
151 88 100       119 return 1 if $child eq '~~';
152 87 100 100     643 return 1 if $child eq '~' && $child->snext_sibling eq '~';
153             }
154             }
155              
156             sub _inchworm_on_a_stick {
157 68     68   126 for my $child ( $_[0]->children ) {
158 373 100       1255 next unless ref($child) eq 'PPI::Token::Operator';
159              
160 82 100 100     134 return 1 if $child eq '~' && $child->snext_sibling eq '-';
161 81 100 100     680 return 1 if $child eq '-' && $child->snext_sibling eq '~';
162             }
163             }
164              
165             sub _space_station {
166 64     64   120 for my $child ( $_[0]->children ) {
167 335 100       1142 next unless ref($child) eq 'PPI::Token::Operator';
168              
169 68 100 100     91 return 1
      66        
170             if $child eq '-'
171             && $child->snext_sibling eq '+'
172             && $child->snext_sibling->snext_sibling eq '-';
173             }
174             }
175              
176             sub _goatse {
177 65     65   105 for my $child ( $_[0]->children ) {
178 328 100       1105 next unless ref($child) eq 'PPI::Structure::List';
179 17 100 100     44 return 1
180             if $child->sprevious_sibling eq '='
181             && $child->snext_sibling eq '=';
182             }
183             }
184              
185             sub _flaming_x_wing {
186 60     60   99 for my $child ( $_[0]->children ) {
187              
188 293 100       596 next unless ref($child) eq 'PPI::Token::QuoteLike::Readline';
189 5 100 66     13 return 1
190             if $child->sprevious_sibling eq '='
191             && $child->snext_sibling eq '=~';
192             }
193             }
194              
195             sub _kite {
196 63     63   113 for my $child ( $_[0]->children ) {
197 334 100       1186 next unless ref($child) eq 'PPI::Token::Operator';
198 64 100 100     84 return 1
199             if $child eq '~~'
200             && $child->snext_sibling eq '<>';
201             }
202             }
203              
204             sub _ornate_double_edged_sword {
205 60     60   106 for my $child ( $_[0]->children ) {
206 288 100       2529 next unless $child eq '<<m';
207 1 50 33     14 return 1
208             if $child->snext_sibling eq '=~'
209             && $child->snext_sibling->snext_sibling eq 'm>>';
210             }
211             }
212              
213             sub _flathead {
214 63     63   96 for my $child ( $_[0]->children ) {
215 314 100       2737 next unless $child eq '-=';
216 2 50       17 return 1 if $child->snext_sibling eq '!';
217             }
218             }
219              
220             sub _phillips {
221 70     70   110 for my $child ( $_[0]->children ) {
222 396 100       3421 next unless $child eq '+=';
223 2 50       17 return 1 if $child->snext_sibling eq '!';
224             }
225             }
226              
227             sub _torx {
228 69     69   102 for my $child ( $_[0]->children ) {
229 383 100       3290 next unless $child eq '*=';
230 2 50       16 return 1 if $child->snext_sibling eq '!';
231             }
232             }
233              
234             sub _pozidriv {
235 70     70   122 for my $child ( $_[0]->children ) {
236 411 100       3582 next unless $child eq 'x=';
237 1 50       10 return 1 if $child->snext_sibling eq '!';
238             }
239             }
240              
241             sub _winking_fat_comma {
242 64     64   106 for my $child ( $_[0]->children ) {
243             next
244 331 100 100     1312 unless ref($child) eq 'PPI::Token::Operator'
245             && $child eq ',';
246 9 100       80 return 1 if $child->snext_sibling eq '=>';
247             }
248             }
249              
250             sub _enterprise {
251 58     58   91 for my $child ( $_[0]->children ) {
252 283 100       1182 next unless $child->class eq 'PPI::Structure::List';
253 14 0 33     55 return 1
      33        
254             if $child->snext_sibling eq 'x'
255             && $child->snext_sibling->snext_sibling eq '!'
256             && $child->snext_sibling->snext_sibling->snext_sibling eq '!';
257             }
258             }
259              
260             sub _key_of_truth {
261 61     61   101 for my $child ( $_[0]->children ) {
262 311 100       1058 next unless $child->class eq 'PPI::Token::Number';
263 6 50 100     19 return 1
      66        
      33        
264             if $child eq '0'
265             && $child->snext_sibling eq '+'
266             && $child->snext_sibling->snext_sibling eq '!'
267             && $child->snext_sibling->snext_sibling->snext_sibling eq '!';
268             }
269             }
270              
271             sub _abbott_and_costello {
272 68     68   124 for my $child ( $_[0]->children ) {
273 394 100       2112 next unless ref($child) eq 'PPI::Token::Operator';
274              
275 88 100 100     109 return 1
      66        
      66        
      66        
276             if ( $child eq '||' || $child eq '//' )
277             && $child->snext_sibling->class eq 'PPI::Structure::List'
278             && ( $child->snext_sibling->content eq '()'
279             || $child->snext_sibling->content eq '( )' );
280              
281             }
282             }
283              
284             1;
285              
286             __END__
287              
288             =pod
289              
290             =encoding UTF-8
291              
292             =head1 NAME
293              
294             Perl::Critic::Policy::Perlsecret - Prevent perlsecrets entering your codebase
295              
296             =head1 VERSION
297              
298             version 0.0.10
299              
300             =head1 SYNOPSIS
301              
302             # in your .perlcriticrc
303             [Perlsecret]
304              
305             # overriding things
306             [Perlsecret]
307             allow_secrets = Bang Bang, Venus
308              
309             =head1 DESCRIPTION
310              
311             This policy checks for L<perlsecret> operators in your code and warns you
312             about them.
313              
314             You can override the secrets that are allowed or disallowed using the
315             parameters C<allow_secrets> and C<disallow_secrets>. The default is to
316             simply disallow everything.
317              
318             Notice the secrets are capitalized correctly ("Ornate Double-Bladed Sword",
319             not "Ornate double-bladed sword").
320              
321             [Perlsecret]
322             disallow_secrets = Flathead, Phillips, Pozidriv, Torx, Enterprise
323              
324             This provides the list to disallow.
325              
326             [Perlsecret]
327             allow_secrets = Bang Bang
328              
329             You can provide both, in which case it will start with the disallow list
330             you provided as the default and then allow everything in the allow list.
331             (There isn't much value to provide both of these.)
332              
333             =head1 NAME
334              
335             Perl::Critic::Policy::Perlsecret - Prevent perlsecrets entering your codebase
336              
337             =head1 VERSION
338              
339             version 0.0.10
340              
341             =head1 AUTHOR
342              
343             Lance Wicks <lancew@cpan.org>
344              
345             =head1 COPYRIGHT AND LICENSE
346              
347             This software is Copyright (c) 2016 by Lance Wicks.
348              
349             This is free software, licensed under:
350              
351             The GNU General Public License, Version 3, June 2007
352              
353             =cut