From 182f015efa0f7a21b7a824fe34b65c9a6a182cae Mon Sep 17 00:00:00 2001 From: Colin Guthrie Date: Mon, 4 Aug 2014 22:41:03 +0100 Subject: Perform some cross checks via bugzilla when publishing advisories --- NEWS | 2 + config_default | 3 + lib/MGA/Advisories.pm | 175 ++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 175 insertions(+), 5 deletions(-) diff --git a/NEWS b/NEWS index a61b76e..893939f 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,5 @@ +- perform some cross checks on bugzilla when publishing advisories + Version 0.17 - add a new tools to actually move the advisories diff --git a/config_default b/config_default index b4cf6bc..f44561d 100644 --- a/config_default +++ b/config_default @@ -20,3 +20,6 @@ advisory_types: prefix: MGAA security: prefix: MGASA +bugzilla_url: https://bugs.mageia.org/xmlrpc.cgi +bugzilla_login: +bugzilla_password: diff --git a/lib/MGA/Advisories.pm b/lib/MGA/Advisories.pm index 689ad59..aaba0f7 100644 --- a/lib/MGA/Advisories.pm +++ b/lib/MGA/Advisories.pm @@ -10,6 +10,8 @@ use Email::Simple; use Email::Simple::Creator; use LWP::UserAgent; use File::Basename; +use HTTP::Cookies; +use XMLRPC::Lite; #use Data::Dump qw(dd); our $config_file = '/usr/share/mga-advisories/config'; @@ -33,6 +35,11 @@ my %tools = ( pkgname => sub { $_[0] =~ m/(.+)-[^-]+-[^-]+/; $1; }, ); +my %bz = ( + proxy => undef, + cookies => undef, +); + my @report_logs; sub report_log { push @report_logs, @_; @@ -55,6 +62,93 @@ sub save_status { DumpFile($statusfile, $advdb->{advisories}{$adv}{status}); } +sub init_bz { + return 1 if ($bz{proxy}); + return 0 if (!$config->{bugzilla_url}); + + my $cookiefile = $ENV{HOME} . '/.mga-advisories/bugzilla-cookies.txt'; + if (!-d dirname($cookiefile)) { + return 0 unless mkdir dirname($cookiefile); + } + + $bz{cookies} = new HTTP::Cookies( + file => $cookiefile, + ignore_discard => 1, + autosave => 1 + ); + + # Q. Do I need to load the cookies or does this happen magically? + + $bz{proxy} = XMLRPC::Lite->proxy( + $config->{bugzilla_url}, + cookie_jar => $bz{cookies} + ); + #$bz{proxy}->import(+trace => 'debug'); + + return 1; +} + +sub call_bz { + my ($method, @args) = @_; + + return 0 if (!init_bz()); + + my $soapresult = $bz{proxy}->call($method, @args); + if ($soapresult->fault) { + if ($soapresult->faultcode == 410) { + # We need to login + + # Q. Do we need to save manually? + $bz{cookies}->save(); + # TODO: chmod the jar... to 600 + + if (login_bz()) { + # Try the call again now we're logged in. + $soapresult = $bz{proxy}->call($method, @args); + return $soapresult->result unless $soapresult->fault; + } + } + + my ($package, $filename, $line) = caller; + report_log( + $soapresult->faultcode . ' ' . $soapresult->faultstring . + " in SOAP call near $filename line $line." + ); + return 0; + } + return $soapresult->result; +} + +sub login_bz { + if ($config->{bugzilla_login} && $config->{bugzilla_password}) { + my $password = $config->{bugzilla_password}; + if ( $password =~ /^file:\/\// ) { + if (open(my $fh, '<:encoding(UTF-8)', substr $password, 7)) { + while (my $row = <$fh>) { + chomp $row; + $password = $row; + last; + } + close $fh; + } else { + print STDERR "Warning: Cannot open bugzilla password file\n"; + return 0; + } + } + my $soapresult = $bz{proxy}->call( + 'User.login', + { + login => $config->{bugzilla_login}, + password => $password, + remember => 1 + } + ); + return 1 unless $soapresult->fault; + } + return 0; +} + + sub get_advisories_from_dir { my %advisories; foreach my $advfile (glob "$config->{advisories_dir}/*.adv") { @@ -83,24 +177,95 @@ sub next_id { } sub assign_id { - my ($bugnum) = @_; - my $advfile = "$config->{advisories_dir}/$bugnum.adv"; + my ($advname) = @_; + my $advfile = "$config->{advisories_dir}/$advname.adv"; $advfile =~ s/\.adv\.adv$/.adv/; my $adv = LoadFile($advfile); if ($adv->{ID}) { - print STDERR "$bugnum already has an ID assigned: $adv->{ID}\n"; + print STDERR "$advname already has an ID assigned: $adv->{ID}\n"; return; } my $type = $config->{advisory_types}{$adv->{type}}{prefix}; if (!$type) { - print STDERR "Unknow type $adv->{type}\n"; + print STDERR "Unknown type $adv->{type}\n"; return; } + + if (!init_bz()) { + print STDERR "Warning: Cannot check bugzilla. Please double check manually\n"; + } else { + # Advisories are not always just [0-9]+.adv, but are + # sometimes [0-9]+.mga3.adv etc. so extract the real bug number + # Perhaps this should actually be the first bug from the advisory references? + my $bugnum = $advname; + $bugnum =~ s/[^0-9]//g; + + if (my $result = call_bz('Bug.get', {ids => [$bugnum]})) { + my $failed = 0; + my $bug = $result->{bugs}->[0]; + print "Found Bug: " . $bug->{summary} . "\n"; + + printf "%-40s", "Checking for QA validation keyword… "; + my $found_keyword = 0; + if (scalar($bug->{keywords}) > 0) { + my $keywords = $bug->{keywords}; + foreach my $keyword (@$keywords) { + if ('validated_update' eq $keyword) { + $found_keyword = 1; + last; + } + } + } + if ($found_keyword) { + print "✔\n"; + } else { + print "✘\n"; + $failed = 1; + } + + printf "%-40s", "Checking dependent bugs… "; + my $depends = $bug->{depends_on}; + if (scalar(@$depends) < 1) { + print "✔ (None found)\n"; + } else { + my $first = 1; + foreach my $dependent_bug_num (@$depends) { + print ', ' if (!$first); + $first = 0; + + if ($result = call_bz('Bug.get', {ids => [$dependent_bug_num]})) { + my $blocking_bug = $result->{bugs}->[0]; + + if ($blocking_bug->{is_open}) { + print "✘ $dependent_bug_num"; + $failed = 1; + } else { + print "✔ $dependent_bug_num"; + } + } else { + print "? $dependent_bug_num\n"; + print STDERR "Error: There was a problem communicating with bugzilla for bug $dependent_bug_num\n"; + return; + } + } + print "\n"; + } + + if ($failed) { + print STDERR "Error: Bugzilla cross check failed.\n"; + return; + } + } else { + print STDERR "Warning: Cannot check bugzilla. Please double check manually\n"; + } + } + + printf "%-40s", "Assigning ID to advisory $advname… "; $adv->{ID} = next_id($type, keys %{get_advisories_from_dir()}); open(my $fh, '>>', $advfile) or die "Error opening $advfile"; print $fh "ID: $adv->{ID}\n"; close $fh; - print "Assigned ID $adv->{ID} to advisory $bugnum\n"; + print "✔ $adv->{ID}\n"; } sub advdb_dumpfile { -- cgit v1.2.1