git/perl/Git/SVN/Prompt.pm
Jeff King 5338ed2b26 perl: check for perl warnings while running tests
We set "use warnings" in most of our perl code to catch problems. But as
the name implies, warnings just emit a message to stderr and don't
otherwise affect the program. So our tests are quite likely to miss that
warnings are being spewed, as most of them do not look at stderr.

We could ask perl to make all warnings fatal, but this is likely
annoying for non-developers, who would rather have a running program
with a warning than something that refuses to work at all.

So instead, let's teach the perl code to respect an environment variable
(GIT_PERL_FATAL_WARNINGS) to increase the severity of the warnings. This
can be set for day-to-day running if people want to be really pedantic,
but the primary use is to trigger it within the test suite.

We could also trigger that for every test run, but likewise even the
tests failing may be annoying to distro builders, etc (just as -Werror
would be for compiling C code). So we'll tie it to a special test-mode
variable (GIT_TEST_PERL_FATAL_WARNINGS) that can be set in the
environment or as a Makefile knob, and we'll automatically turn the knob
when DEVELOPER=1 is set. That should give developers and CI the more
careful view without disrupting normal users or packagers.

Note that the mapping from the GIT_TEST_* form to the GIT_* form in
test-lib.sh is necessary even if they had the same name: the perl
scripts need it to be normalized to a perl truth value, and we also have
to make sure it's exported (we might have gotten it from the
environment, but we might also have gotten it from GIT-BUILD-OPTIONS
directly).

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-10-21 23:11:48 -07:00

184 lines
5.2 KiB
Perl

package Git::SVN::Prompt;
use strict;
use warnings $ENV{GIT_PERL_FATAL_WARNINGS} ? qw(FATAL all) : ();
require SVN::Core;
use vars qw/$_no_auth_cache $_username/;
sub simple {
my ($cred, $realm, $default_username, $may_save, $pool) = @_;
$may_save = undef if $_no_auth_cache;
$default_username = $_username if defined $_username;
if (defined $default_username && length $default_username) {
if (defined $realm && length $realm) {
print STDERR "Authentication realm: $realm\n";
STDERR->flush;
}
$cred->username($default_username);
} else {
username($cred, $realm, $may_save, $pool);
}
$cred->password(_read_password("Password for '" .
$cred->username . "': ", $realm));
$cred->may_save($may_save);
$SVN::_Core::SVN_NO_ERROR;
}
sub ssl_server_trust {
my ($cred, $realm, $failures, $cert_info, $may_save, $pool) = @_;
$may_save = undef if $_no_auth_cache;
print STDERR "Error validating server certificate for '$realm':\n";
{
no warnings 'once';
# All variables SVN::Auth::SSL::* are used only once,
# so we're shutting up Perl warnings about this.
if ($failures & $SVN::Auth::SSL::UNKNOWNCA) {
print STDERR " - The certificate is not issued ",
"by a trusted authority. Use the\n",
" fingerprint to validate ",
"the certificate manually!\n";
}
if ($failures & $SVN::Auth::SSL::CNMISMATCH) {
print STDERR " - The certificate hostname ",
"does not match.\n";
}
if ($failures & $SVN::Auth::SSL::NOTYETVALID) {
print STDERR " - The certificate is not yet valid.\n";
}
if ($failures & $SVN::Auth::SSL::EXPIRED) {
print STDERR " - The certificate has expired.\n";
}
if ($failures & $SVN::Auth::SSL::OTHER) {
print STDERR " - The certificate has ",
"an unknown error.\n";
}
} # no warnings 'once'
printf STDERR
"Certificate information:\n".
" - Hostname: %s\n".
" - Valid: from %s until %s\n".
" - Issuer: %s\n".
" - Fingerprint: %s\n",
map $cert_info->$_, qw(hostname valid_from valid_until
issuer_dname fingerprint);
my $choice;
prompt:
my $options = $may_save ?
"(R)eject, accept (t)emporarily or accept (p)ermanently? " :
"(R)eject or accept (t)emporarily? ";
STDERR->flush;
$choice = lc(substr(Git::prompt("Certificate problem.\n" . $options) || 'R', 0, 1));
if ($choice eq 't') {
$cred->may_save(undef);
} elsif ($choice eq 'r') {
return -1;
} elsif ($may_save && $choice eq 'p') {
$cred->may_save($may_save);
} else {
goto prompt;
}
$cred->accepted_failures($failures);
$SVN::_Core::SVN_NO_ERROR;
}
sub ssl_client_cert {
my ($cred, $realm, $may_save, $pool) = @_;
$may_save = undef if $_no_auth_cache;
print STDERR "Client certificate filename: ";
STDERR->flush;
chomp(my $filename = <STDIN>);
$cred->cert_file($filename);
$cred->may_save($may_save);
$SVN::_Core::SVN_NO_ERROR;
}
sub ssl_client_cert_pw {
my ($cred, $realm, $may_save, $pool) = @_;
$may_save = undef if $_no_auth_cache;
$cred->password(_read_password("Password: ", $realm));
$cred->may_save($may_save);
$SVN::_Core::SVN_NO_ERROR;
}
sub username {
my ($cred, $realm, $may_save, $pool) = @_;
$may_save = undef if $_no_auth_cache;
if (defined $realm && length $realm) {
print STDERR "Authentication realm: $realm\n";
}
my $username;
if (defined $_username) {
$username = $_username;
} else {
$username = Git::prompt("Username: ");
}
$cred->username($username);
$cred->may_save($may_save);
$SVN::_Core::SVN_NO_ERROR;
}
sub _read_password {
my ($prompt, $realm) = @_;
my $password = Git::prompt($prompt, 1);
$password;
}
1;
__END__
=head1 NAME
Git::SVN::Prompt - authentication callbacks for git-svn
=head1 SYNOPSIS
use Git::SVN::Prompt qw(simple ssl_client_cert ssl_client_cert_pw
ssl_server_trust username);
use SVN::Client ();
my $cached_simple = SVN::Client::get_simple_provider();
my $git_simple = SVN::Client::get_simple_prompt_provider(\&simple, 2);
my $cached_ssl = SVN::Client::get_ssl_server_trust_file_provider();
my $git_ssl = SVN::Client::get_ssl_server_trust_prompt_provider(
\&ssl_server_trust);
my $cached_cert = SVN::Client::get_ssl_client_cert_file_provider();
my $git_cert = SVN::Client::get_ssl_client_cert_prompt_provider(
\&ssl_client_cert, 2);
my $cached_cert_pw = SVN::Client::get_ssl_client_cert_pw_file_provider();
my $git_cert_pw = SVN::Client::get_ssl_client_cert_pw_prompt_provider(
\&ssl_client_cert_pw, 2);
my $cached_username = SVN::Client::get_username_provider();
my $git_username = SVN::Client::get_username_prompt_provider(
\&username, 2);
my $ctx = new SVN::Client(
auth => [
$cached_simple, $git_simple,
$cached_ssl, $git_ssl,
$cached_cert, $git_cert,
$cached_cert_pw, $git_cert_pw,
$cached_username, $git_username
]);
=head1 DESCRIPTION
This module is an implementation detail of the "git svn" command.
It implements git-svn's authentication policy. Do not use it unless
you are developing git-svn.
The interface will change as git-svn evolves.
=head1 DEPENDENCIES
L<SVN::Core>.
=head1 SEE ALSO
L<SVN::Client>.
=head1 INCOMPATIBILITIES
None reported.
=head1 BUGS
None.