Repository navigation
stop using Safe.pm - #599
Conversation
Nothing has called this for years. It evaluated a user-supplied $VERSION right-hand side in a Safe compartment, so deleting it removes one more place where uploaded code gets run. Co-Authored-By: Claude <noreply@anthropic.com>
parse_version calls Safe->new, but this file only ever loaded Safe from inside the dead _module_version, and so really relied on PAUSE::mldistwatch having loaded it first. Co-Authored-By: Claude <noreply@anthropic.com>
To find a module's version, the indexer used to evaluate the uploaded
file's $VERSION line in a Safe compartment, in a forked child running as
an unprivileged user. That amounted to running uploaded code, with Safe
as the main barrier. The thing is, Safe isn't really meant to be this
kind of safety mechanism. We should not rely on it preventing real
problems.
With this commit, the line is only ever parsed, and the parse results
turned into the indexed version.
The line is chosen exactly as before, but it's only accepted if it
assigns a literal to the package's $VERSION, either bare (for no strict
or "use vars") or with an "our" declaration. The right hand side of
the assignment must be either:
* '...' or "..." or q/qq operator using one of [] () {} <> and
not using interpolation or escaping
* a decimal number
It may, optionally, be passed to version->declare, ->new, ->parse, or
the qv() function. Either lhs or rhs may be parenthesized.
Anything else is refused, and the uploader's report shows the offending
line and explains how to fix it: use a literal, use "package NAME
VERSION", or use META provides.
For every line that's still accepted, the version found is the same as
before (checked against the old code), except that "package Foo; our
$VERSION = '1.0';" on one line now gives 1.0 where it used to give
undef. (Who would do such a thing? Well, they'll get a better result
now, if they do it.)
The forked child, the Safe compartment, and the setuid to ML_CHOWN_USER
are all gone.
Co-Authored-By: Claude <noreply@anthropic.com>
Nothing here uses it. PAUSE::pmfile used to rely on it having been loaded, but no longer uses it either. Co-Authored-By: Claude <noreply@anthropic.com>
parse_version used to return a JSON string in place of a version when it
couldn't find one. That made sense when the result came back over a
pipe from a forked child, but the child is gone. The string still
travelled as though it were a version: through $self->{VERSION}, into
each package's version in packages_per_pmfile, and finally to
PAUSE::package, which spotted the leading brace and decoded it.
That caused a few problems:
* the JSON appeared in the uploader's report as the package's version
* in packages_per_pmfile, the JSON string compared "gt" any real
version, so it beat a "package NAME VERSION" version
* normalize_version passed through anything shaped like a JSON object,
including a META provides version, which would then die in decoding
Now parse_version returns a hashref holding either the version or the
package error to report. examine_fio passes that to packages_per_pmfile
instead of setting $self->{VERSION}, and each package that would take
the file's version gets the error in its package data, which
PAUSE::package uses directly.
Co-Authored-By: Claude <noreply@anthropic.com>
rspier
left a comment
There was a problem hiding this comment.
Looks good.
Is there user documentation that needs to be updated somewhere? (Possibly in a follow-up PR.)
|
Nice work on this — replacing the A few review notes: 1. Boolean check on
|
Annoyingly, version.pm objects overload bool, so that "version 0" is false. This is painful, but it is the reality we live in. Don't test a version object for truth, test for definedness. Co-Authored-By: Claude <noreply@anthropic.com>
A line like "$flag = 1; # note: $VERSION = 1.0 below" was taken as the version line, because the selection regex matched the commented-out assignment. Since the first selected line decides the result, it was then refused, and the real assignment further down was never seen. Now the selection looks only at the part of the line before a comment. This wasn't a new bug in this branch, but as long as we're in here... The comment detection is approximate, but neither of its failure cases appears in any version line in the latest releases on CPAN. Co-Authored-By: Claude <noreply@anthropic.com>
|
I think this is a good idea overall. I would just make two suggestions for community outreach (I know, well volunteered):
|
Rather than falling back to evaluating VERSION assignments inside a forked Safe compartment, just don't. Instead, refuse to index, giving the authors instructions on how to assign a version that can be statically indexed.