/usr/share/perl5/Path/IsDev.pm is in libpath-isdev-perl 1.000002-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 | use strict;
use warnings;
package Path::IsDev;
BEGIN {
$Path::IsDev::AUTHORITY = 'cpan:KENTNL';
}
{
$Path::IsDev::VERSION = '1.000002';
}
# ABSTRACT: Determine if a given Path resembles a development source tree
use Sub::Exporter -setup => { exports => [ is_dev => \&_build_is_dev, ], };
our $ENV_KEY_DEBUG = 'PATH_ISDEV_DEBUG';
our $DEBUG = ( exists $ENV{$ENV_KEY_DEBUG} ? $ENV{$ENV_KEY_DEBUG} : undef );
sub debug {
return unless $DEBUG;
return *STDERR->printf( qq{[Path::IsDev] %s\n}, shift );
}
sub _build_is_dev {
my ( $class, $name, $arg ) = @_;
my $object;
return sub {
my ($path) = @_;
$object ||= do {
require Path::IsDev::Object;
Path::IsDev::Object->new( %{ $arg || {} } );
};
return $object->matches($path);
};
}
*is_dev = _build_is_dev( 'Path::IsDev', 'is_dev', {} );
1;
__END__
=pod
=encoding UTF-8
=head1 NAME
Path::IsDev - Determine if a given Path resembles a development source tree
=head1 VERSION
version 1.000002
=head1 SYNOPSIS
use Path::IsDev qw(is_dev);
if( is_dev('/some/path') ) {
...
} else {
...
}
=head1 DESCRIPTION
This module is more or less a bunch of heuristics for determining if a given path
is a development tree root of some kind.
This has many useful applications, notably ones that require behaviours for "installed"
modules to be different to those that are still "in development"
=head1 FUNCTIONS
=head2 debug
Debug callback.
To enable debugging:
export PATH_ISDEV_DEBUG=1
=head2 C<is_dev>
Using an C<import>'ed C<is_dev>:
if( is_dev( $path ) ) {
}
Though the actual heuristics used will be based on how C<import> was called.
Additionally, you can call
Path::IsDev::is_dev
without C<import>ing anything, and it will behave exactly the same as if you'd imported
it using
use Path::IsDev qw( is_dev );
That is, no C<set> specification is applicable, so you'll only get the "default".
=head1 UNDERSTANDING AND DEBUGGING THIS MODULE
Understanding how this module works, is critical to understand where you can use it, and the consequences of using it.
This module operates on a very simplistic level, and its easy for false-positives to occur.
There are two types of Heuristics, Postive/Confirming Heuristics, and Negative/Disconfirming Heuristics.
Positive Heuristics and Negative Heuristics are based solely on the presence of specific marker files in a directory, or special marker directories.
For instance, the files C<META.yml>, C<Makefile.PL>, and C<Build.PL> are all B<Positive Heuristic> markers, because their presence
often indicates a "root" of a development tree.
And for instance, the directories C<t/>, C<xt/> and C<.git/> are also B<Positive Heuristic> markers, because these structures
are common in C<perl> development trees, and uncommon in install trees.
However, these markers sometimes go wrong, for instance, consider you have a C<local::lib> or C<perlbrew> install in C<$HOME>
$HOME/
$HOME/lib/
$HOME/perl5/perls/perl-5.19.3/lib/site_perl/
Etc.
Under normal circumstances, neither C<$HOME> nor those 3 paths are considered C<dev>.
However, all it takes to cause a false positive, is for somebody to install a C<t> or C<xt> directory, or a marker file in one of the
above directories for C<path_isdev($dir)> to return true.
This may not be a problem, at least, until you use C<Path::FindDev> which combines C<Path::IsDev> with recursive up-level traversal.
$HOME/
$HOME/lib/
$HOME/perl5/perls/perl-5.19.3/lib/site_perl/
find_dev('$HOME/perl5/perls/perl-5.19.3/lib/site_perl/') # returns false, because it is not inside a dev directory
mkdir $HOME/t
find_dev('$HOME/perl5/perls/perl-5.19.3/lib/site_perl/') # returns $HOME, because $HOME/t exists.
And it is this kind of problem that usually catches people off guard.
PATH_ISDEV_DEBUG=1 perl -Ilib -MPath::FindDev=find_dev -E "say find_dev(q{/home/kent/perl5/perlbrew/perls/perl-5.19.3/lib/site_perl})"
...
[Path::IsDev=0] + ::Tool::Dzil => 0 : dist.ini does not exist
[Path::IsDev=0] + ::Tool::MakeMaker => 0 : Makefile.PL does not exist
[Path::IsDev=0] + ::Tool::ModuleBuild => 0 : Build.PL does not exist
[Path::IsDev=0] + ::META => 0 : META.json does not exist
[Path::IsDev=0] + ::META => 1 : META.yml exists
[Path::IsDev=0] + ::META => 1 : /home/kent/perl5/META.yml is a file
[Path::IsDev=0] + ::META matched path /home/kent/perl5
/home/kent/perl5
Whoops!.
[Path::IsDev=0] + ::META => 1 : META.yml exists
[Path::IsDev=0] + ::META => 1 : /home/kent/perl5/META.yml is a file
No wonder!
rm /home/kent/perl5/META.yml
PATH_ISDEV_DEBUG=1 perl -Ilib -MPath::FindDev=find_dev -E "say find_dev(q{/home/kent/perl5/perlbrew/perls/perl-5.19.3/lib/site_perl})"
...
[Path::IsDev=0] Matching /home/kent/perl5
...
[Path::IsDev=0] + ::TestDir => 0 : xt does not exist
[Path::IsDev=0] + ::TestDir => 1 : t exists
[Path::IsDev=0] + ::TestDir => 1 : /home/kent/perl5/t is a dir
[Path::IsDev=0] + ::TestDir matched path /home/kent/perl5
/home/kent/perl5
Double whoops!
[Path::IsDev=0] + ::TestDir => 1 : t exists
[Path::IsDev=0] + ::TestDir => 1 : /home/kent/perl5/t is a dir
And you could keep doing that until you rule out all the bad heuristics in your tree.
Or, you could use a negative heuristic.
touch /home/kent/perl5/.path_isdev_ignore
PATH_ISDEV_DEBUG=1 perl -Ilib -MPath::FindDev=find_dev -E "say find_dev(q{/home/kent/perl5/perlbrew/perls/perl-5.19.3/lib/site_perl})"
...
[Path::IsDev=0] Matching /home/kent/perl5
[Path::IsDev=0] - ::IsDev::IgnoreFile => 1 : .path_isdev_ignore exists
[Path::IsDev=0] - ::IsDev::IgnoreFile => 1 : /home/kent/perl5/.path_isdev_ignore is a file
[Path::IsDev=0] - ::IsDev::IgnoreFile excludes path /home/kent/perl5
[Path::IsDev=0] no match found
...
[Path::IsDev=0] Matching /
...
[Path::IsDev=0] no match found
Success!
[Path::IsDev=0] - ::IsDev::IgnoreFile => 1 : .path_isdev_ignore exists
[Path::IsDev=0] - ::IsDev::IgnoreFile => 1 : /home/kent/perl5/.path_isdev_ignore is a file
=head1 HEURISTICS
=head2 Negative Heuristics bundled with this distribution
Just remember, a B<Negative> Heuristic B<excludes the path it is associated with>
=over 4
=item * L<< C<IsDev::IgnoreFile>|Path::IsDev::NegativeHeuristic::IsDev::IgnoreFile >> - C<.path_isdev_ignore>
=back
=head2 Positive Heuristics bundled with this distribution
=over 4
=item * L<< C<Changelog>|Path::IsDev::Heuristic::Changelog >> - Files matching C<Changes>, C<Changelog>, and similar, case insensitive, extensions optional.
=item * L<< C<DevDirMarker>|Path::IsDev::Heuristic::DevDirMarker >> - explicit C<.devdir> file to indicate a project root.
=item * L<< C<META>|Path::IsDev::Heuristic::META >> - C<META.yml>/C<META.json>
=item * L<< C<MYMETA>|Path::IsDev::Heuristic::MYMETA >> - C<MYMETA.yml>/C<MYMETA.json>
=item * L<< C<Makefile>|Path::IsDev::Heuristic::Makefile >> - Any C<Makefile> format documented supported by GNU Make
=item * L<< C<TestDir>|Path::IsDev::Heuristic::TestDir >> - A directory called either C<t/> or C<xt/>
=item * L<< C<Tool::DZil>|Path::IsDev::Heuristic::Tool::DZil >> - A C<dist.ini> file
=item * L<< C<Tool::MakeMaker>|Path::IsDev::Heuristic::Tool::MakeMaker >> - A C<Makefile.PL> file
=item * L<< C<Tool::ModuleBuild>|Path::IsDev::Heuristic::Tool::ModuleBuild >> - A C<Build.PL> file
=item * L<< C<VCS::Git>|Path::IsDev::Heuristic::VCS::Git >> - A C<.git> directory
=back
=head1 HEURISTIC SETS
=head2 Heuristic Sets Bundled with this distribution
=over 4
=item * L<< C<Basic>|Path::IsDev::HeuristicSet::Basic >> - The basic heuristic set that contains most, if not all heuristics.
=back
=head1 ADVANCED USAGE
=head2 Custom Sets
C<Path::IsDev> has a system of "sets" of Heuristics, in order to allow for pluggable
and flexible heuristic types.
Though, for the vast majority of cases, this is not required.
use Path::IsDev is_dev => { set => 'Basic' };
use Path::IsDev is_dev => { set => 'SomeOtherSet' , -as => 'is_dev_other' };
=head2 Overriding the default set
If for whatever reason the C<Basic> set is insufficient, or if it false positives on your system for some reason,
the "default" set can be overridden.
export PATH_ISDEV_DEFAULT_SET="SomeOtherSet"
...
use Path::IsDev qw( is_dev );
is_dev('/some/path') # uses SomeOtherSet
Though this will only take priority in the event the set is not specified during C<import>
If this poses a security concern for the user, then this security hole can be eliminated by declaring the set you want in code:
export PATH_ISDEV_DEFAULT_SET="SomeOtherSet"
...
use Path::IsDev is_dev => { set => 'Basic' };
is_dev('/some/path') # uses Basic, regardless of ENV
=head1 SECURITY
Its conceivable, than an evil user could construct an evil set, containing arbitrary and vulnerable code,
and possibly stash that evil set in a poorly secured privileged users @INC
And if they managed to achieve that, if they could poison the privileged users %ENV, they could trick the privileged user into executing arbitrary code.
Though granted, if you can do either of those 2 things, you're probably security vulnerable anyway, and granted, if you could do either of those 2 things you could do much more evil things by the following:
export PERL5OPT="-MEvil::Module"
So with that in understanding, saying this modules default utility is "insecure" is mostly a bogus argument.
And to that effect, this module does nothing to "lock down" that mechanism, and this module encourages you
to B<NOT> force a set, unless you B<NEED> to, and strongly suggests that forcing a set for the purpose of security will achieve no real improvement in security, while simultaneously reducing utility.
=begin MetaPOD::JSON v1.1.0
{
"namespace":"Path::IsDev",
"interface":"exporter"
}
=end MetaPOD::JSON
=head1 AUTHOR
Kent Fredric <kentfredric@gmail.com>
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2013 by Kent Fredric <kentfredric@gmail.com>.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut
|