File Coverage

blib/lib/File/OSS/Scan/Ruleset.pm
Criterion Covered Total %
statement 24 91 26.3
branch 0 28 0.0
condition 0 11 0.0
subroutine 8 11 72.7
pod 0 3 0.0
total 32 144 22.2


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             File::OSS::Scan::Ruleset - initialize the scan rules
4              
5             =head1 VERSION
6              
7             version 0.04
8              
9             =head1 SYNOPSIS
10              
11             use File::OSS::Scan::Ruleset;
12              
13             File::OSS::Scan::Ruleset->init($config_file);
14             my $ruleset = File::OSS::Scan::Ruleset->get_ruleset();
15              
16             =head1 DESCRIPTION
17              
18             This is an internal module used by L to initialise scan rules from
19             the configuration file, and should not be called directly.
20              
21             =head1 SEE ALSO
22              
23             =over 4
24              
25             =item * L
26              
27             =back
28              
29             =head1 AUTHOR
30              
31             Harry Wang
32              
33             =head1 COPYRIGHT AND LICENSE
34              
35             This software is Copyright (c) 2014 by Harry Wang.
36              
37             This is free software, licensed under:
38              
39             Artistic License 1.0
40              
41             =cut
42              
43             package File::OSS::Scan::Ruleset;
44              
45 1     1   6 use strict;
  1         3  
  1         40  
46 1     1   5 use warnings FATAL => 'all';
  1         2  
  1         45  
47              
48 1     1   5 use Fatal qw( open close );
  1         1  
  1         18  
49 1     1   4450 use Carp;
  1         3  
  1         93  
50 1     1   7 use English qw( -no_match_vars );
  1         3  
  1         9  
51 1     1   623 use Data::Dumper; # for debug
  1         2  
  1         87  
52              
53 1     1   7 use File::OSS::Scan::Constant qw(:all);
  1         2  
  1         1274  
54              
55             our $VERSION = '0.04';
56              
57             my $cfg_default = $ENV{OSSSCAN_CONFIG} || ".ossscan.rc";
58             my @valid_sections = qw/GLOBAL FILE DIRECTORY LINE/;
59              
60             # global var ...
61             our $ruleset = undef;
62              
63             sub init {
64 0     0 0   my $self = shift;
65 0   0       my $config_file = shift || $cfg_default;
66              
67 0           local *CONFIG;
68              
69 0 0         if ( ! -f $config_file ) {
70 0           carp "config file $config_file doesn't exist, using the embedded ruleset.";
71              
72             # read from __DATA__ section
73 0           *CONFIG = *DATA;
74             }
75             else {
76 0 0         croak "config file $config_file is not readable."
77             if ( ! -r $config_file );
78              
79 0 0         open( CONFIG, $config_file ) ||
80             croak "Can't open $config_file, $!.";
81             }
82              
83             # clear previously set config $ruleset
84 0           undef $ruleset;
85              
86 0           my ( $section, $rule ) = ( undef, undef );
87 0           my $invalid_section_flag = UNI_FALSE;
88              
89 0           while() {
90 0           chomp; # remove newline
91 0           s/#.*//; # remove comments
92 0           s/^\s+//; # remove leading spaces
93 0           s/\s+$//; # remove trailing spaces
94              
95             # anything left ?
96 0 0         next unless length;
97              
98             # parse sections
99 0 0         if ( /^\[(\w+)\].*/ ) {
100 0           $section = uc $1;
101              
102             # skip invalid sections
103 0 0         if ( ! grep {/^$section$/} @valid_sections ) {
  0            
104 0           carp "Invalid section name $section, skipping ...";
105 0           $invalid_section_flag = UNI_TRUE;
106 0           next;
107             } else {
108 0           $invalid_section_flag = UNI_FALSE;
109             }
110              
111 0 0         $ruleset->{$section} = undef
112             if ( not exists $ruleset->{$section} );
113             }
114              
115             # parse settings
116             # put them all under 'GLOBAL' section
117 0 0         if ( /^(\w+)\s*\:\s*(.*)$/ ) {
118 0           my ( $key, $val ) = ( $1, $2 );
119 0           $ruleset->{'GLOBAL'}->{$key} = [ split /\s+/, $val ];
120             }
121              
122             # parse rules
123             # if ( /^([\w\%\-\s]+)$/ ) {
124 0 0         if ( /^(\d+\%?.*)$/ ) {
125 0           $rule = $1;
126              
127             # skip rules under invalid sections
128 0 0         if ( $invalid_section_flag ) {
129 0           carp "also skipping rules $rule under invalid section $section ...";
130 0           next;
131             }
132              
133 0   0       my $cur_section = $section || 'GLOBAL';
134              
135 0           my ( $certain, $func, @args )
136             = split(' ', $rule);
137              
138             # valid level of certainty: 0 - 100
139 0 0         if ( $certain =~ /^(\d+)\%?$/ ) {
140 0           $certain = $1;
141              
142 0 0 0       if ( $certain > 100 or $certain < 0 ) {
143 0           carp "certainty $certain is not in the range of 0 to 100, skipping rules $rule ...";
144 0           next;
145             }
146             }
147             else {
148 0           carp "invalid level of certainty $certain, skipping rules $rule ...";
149 0           next;
150             }
151              
152 0           my $hash = {
153             'cert' => $certain,
154             'func' => $func,
155             'args' => \@args
156             };
157              
158 0           push @{$ruleset->{$cur_section}}, $hash;
  0            
159             }
160              
161             }
162              
163 0           close( CONFIG );
164              
165             # sort rulesets by certainty level
166 0           sort_ruleset();
167              
168 0           return SUCCESS;
169             }
170              
171             sub get_ruleset {
172 0     0 0   my $var = $_[0] . "::ruleset";
173 1     1   10 no strict 'refs';
  1         2  
  1         555  
174 0           return $$var;
175             }
176              
177             sub sort_ruleset {
178              
179             # sort every sections of ruleset according to
180             # its level of certainty.
181 0     0 0   foreach my $sec ( @valid_sections ) {
182              
183             # don't sort global setting
184             next
185 0 0         if ( $sec eq 'GLOBAL' );
186              
187 0 0 0       if ( exists $ruleset->{$sec} and
188             defined $ruleset->{$sec} ) {
189              
190 0           my @sorted = ();
191 0           my %raw_hash = ();
192 0           my $rules = $ruleset->{$sec};
193              
194 0           foreach my $rule ( @$rules ) {
195 0           my $cert = $rule->{'cert'};
196 0           push @{$raw_hash{$cert}}, $rule;
  0            
197             }
198              
199 0           foreach my $s_cert ( sort { $b <=> $a } keys %raw_hash ) {
  0            
200 0           push @sorted, @{$raw_hash{$s_cert}};
  0            
201             }
202              
203 0           $ruleset->{$sec} = \@sorted;
204             }
205             }
206              
207 0           return SUCCESS;
208             }
209              
210              
211             1;
212              
213              
214              
215             __DATA__