#!/usr/bin/env perl
use
5.014002;
our
$VERSION
=
"0.10 - 20240428"
;
our
$CMD
= $0 =~ s{.*/}{}r;
sub
usage {
my
$err
=
shift
and
select
STDERR;
say
"usage: $CMD [options] [file | module | dir ...]"
;
say
" -d --deps Report on current deps too"
;
say
" -m --minimum Report based on minimum (default recommended)"
;
say
" -j F --json=F Use downloaded JSON instead of fetching"
;
say
" -p --perl Report CVE's on required perl (default OFF)"
;
say
" -c --corelist Replace 0 versions w*ith CORE version"
;
say
" -v[#] --verbose[=#] Set verbosity level"
;
say
" -J F --json-out=F Output in JSON file F (- = STDOUT)"
;
say
""
;
say
"For CVE's in the perl core, please use --perl and/or CPAN::Audit"
;
say
"Documentation should still be written"
;
exit
$err
;
}
use
Cwd
qw( getcwd abs_path)
;
GetOptions (
"help|?"
=>
sub
{ usage (0); },
"V|version"
=>
sub
{
say
"$CMD [$VERSION]"
;
exit
0; },
"d|deps!"
=> \
my
$opt_d
,
"m|minimum!"
=> \
my
$opt_m
,
"j|json=s"
=> \
my
$opt_j
,
"J|json-out=s"
=> \
my
$opt_J
,
"p|perl!"
=> \
my
$opt_p
,
"c|cl|corelist!"
=> \
my
$opt_c
,
"v|verbose:1"
=> \(
my
$opt_v
= 0),
) or usage (1);
@ARGV
or
push
@ARGV
=>
"."
;
my
$tld
= abs_path (getcwd);
my
%rpt
;
foreach
my
$module
(
@ARGV
) {
my
$cve
= Test::CVE->new (
deps
=>
$opt_d
,
perl
=>
$opt_p
// 0,
core
=>
$opt_c
// 0,
minimum
=>
$opt_m
,
cpansa
=>
$opt_j
,
verbose
=>
$opt_v
,
);
chdir
$tld
;
if
(-d
$module
) {
chdir
$module
;
}
elsif
(-s
$module
and
open
my
$fh
,
"<"
,
$module
) {
my
%mod
;
my
$pl
=
do
{
local
$/; <
$fh
> } =~ s/^\s*
my
$v
=
$pl
=~ m/\$\s
*VERSION
\s*=\s*[
"']?(\S+?)['"
]?\s*;/ ? $1 :
"-"
;
$cve
->set_meta (
$module
,
$v
);
while
(
$pl
=~ m{\b (?:
use
|
require
) [\s\r\n]+
([\w:]+)
([\s\r\n]+[.\w]+)?
(?: [\s\r\n]+ (?:
"[^;]+"
|
'[^;]+'
|
qw[^;]
+ ))?
[\s\r\n]*;
}gx) {
my
(
$m
,
$v
) = ($1, $2 // 0);
$m
=~ m/^(?: v?5 | warnings | strict )$/x and
next
;
$cve
->want (
$m
,
$v
);
}
}
else
{
usage (1);
}
unless
(
$opt_J
) {
$cve
->test->report;
next
;
}
my
@err
;
local
$SIG
{__WARN__} =
sub
{
push
@err
=>
map
{
s/[\s\r\n]+\z//r =~ s{[\s\r\n]+at\s+\S+\s+line\s+[0-9]+}{}r
}
@_
;
};
say
$module
;
eval
{
$rpt
{
$module
} = [
$cve
->test->cve ]; };
@err
and
$rpt
{
$module
} = [{
error
=> [
@err
] }];
}
chdir
$tld
;
if
(
$opt_J
) {
if
(
$opt_J
eq
"-"
) {
say
encode_json (\
%rpt
);
}
else
{
open
my
$fh
,
">:encoding(utf-8)"
,
$opt_J
or
die
"$opt_J: $!\n"
;
say
$fh
encode_json (\
%rpt
);
close
$fh
;
}
}