diff options
Diffstat (limited to 'extensions/Push')
-rw-r--r-- | extensions/Push/lib/Connector/ReviewBoard.pm | 214 | ||||
-rw-r--r-- | extensions/Push/lib/Connector/ReviewBoard/Client.pm | 78 | ||||
-rw-r--r-- | extensions/Push/lib/Connector/ReviewBoard/Resource.pm | 38 | ||||
-rw-r--r-- | extensions/Push/lib/Connector/ReviewBoard/ReviewRequest.pm | 28 |
4 files changed, 102 insertions, 256 deletions
diff --git a/extensions/Push/lib/Connector/ReviewBoard.pm b/extensions/Push/lib/Connector/ReviewBoard.pm index b5d1a9214..97f489826 100644 --- a/extensions/Push/lib/Connector/ReviewBoard.pm +++ b/extensions/Push/lib/Connector/ReviewBoard.pm @@ -12,67 +12,88 @@ use warnings; use base 'Bugzilla::Extension::Push::Connector::Base'; +use Bugzilla::Bug; +use Bugzilla::BugMail; +use Bugzilla::Component; use Bugzilla::Constants; use Bugzilla::Extension::Push::Constants; use Bugzilla::Extension::Push::Util; -use Bugzilla::Bug; -use Bugzilla::Attachment; -use Bugzilla::Extension::Push::Connector::ReviewBoard::Client; - -use JSON 'decode_json'; -use DateTime; -use Scalar::Util 'blessed'; +use Bugzilla::Group; +use Bugzilla::Product; +use Bugzilla::User; +use Bugzilla::Util qw( trim ); use constant RB_CONTENT_TYPE => 'text/x-review-board-request'; - -sub client { - my $self = shift; - - $self->{client} //= Bugzilla::Extension::Push::Connector::ReviewBoard::Client->new( - base_uri => $self->config->{base_uri}, - username => $self->config->{username}, - password => $self->config->{password}, - $self->config->{proxy} ? (proxy => $self->config->{proxy}) : (), - ); - - return $self->{client}; -} +use constant AUTOMATION_USER => 'automation@bmo.tld'; sub options { return ( { - name => 'base_uri', - label => 'Base URI for ReviewBoard', + name => 'product', + label => 'Product to create bugs in', type => 'string', - default => 'https://reviewboard.allizom.org', + default => 'Developer Services', required => 1, + validate => sub { + Bugzilla::Product->new({ name => $_[0] }) + || die "Invalid Product ($_[0])\n"; + }, }, { - name => 'username', - label => 'Username', + name => 'component', + label => 'Component to create bugs in', type => 'string', - default => 'guest', + default => 'MozReview', required => 1, + validate => sub { + my ($component, $config) = @_; + my $product = Bugzilla::Product->new({ name => $config->{product} }) + || die "Invalid Product (" . $config->{product} . ")\n"; + Bugzilla::Component->new({ product => $product, name => $component }) + || die "Invalid Component ($component)\n"; + }, }, { - name => 'password', - label => 'Password', - type => 'password', - default => 'guest', + name => 'version', + label => "The bug's version", + type => 'string', + default => 'Production', required => 1, + validate => sub { + my ($version, $config) = @_; + my $product = Bugzilla::Product->new({ name => $config->{product} }) + || die "Invalid Product (" . $config->{product} . ")\n"; + Bugzilla::Version->new({ product => $product, name => $version }) + || die "Invalid Version ($version)\n"; + }, }, { - name => 'proxy', - label => 'Proxy', - type => 'string', + name => 'group', + label => 'Security group', + type => 'string', + default => 'mozilla-employee-confidential', + required => 1, + validate => sub { + Bugzilla::Group->new({ name => $_[0] }) + || die "Invalid Group ($_[0])\n"; + }, + }, + { + name => 'cc', + label => 'Comma separated list of users to CC', + type => 'string', + default => '', + required => 1, + validate => sub { + foreach my $login (map { trim($_) } split(',', $_[0])) { + Bugzilla::User->new({ name => $login }) + || die "Invalid User ($login)\n"; + } + }, }, ); } -sub stop { - my ($self) = @_; -} - sub should_send { my ($self, $message) = @_; @@ -102,86 +123,55 @@ sub send { my $payload = $message->payload_decoded(); my $target = $payload->{event}->{target}; - if (my $method = $self->can("_process_$target")) { - $self->$method($payload->{$target}); + # load attachments + my $bug_id = $target eq 'bug' ? $payload->{bug}->{id} : $payload->{attachment}->{bug}->{id}; + my $attach_id = $target eq 'attachment' ? $payload->{attachment}->{id} : undef; + Bugzilla->set_user(Bugzilla::User->super_user); + my $bug = Bugzilla::Bug->new({ id => $bug_id, cache => 1 }); + Bugzilla->logout; + + # create a bug if there are any mozreview attachments + my @reviews = grep { $_->contenttype eq RB_CONTENT_TYPE } @{ $bug->attachments }; + if (@reviews) { + + # build comment + my $comment = $target eq 'bug' + ? "Bug $bug_id has MozReview reviews and is no longer public." + : "MozReview attachment $attach_id on Bug $bug_id is no longer public."; + $comment .= "\n\n"; + foreach my $attachment (@reviews) { + $comment .= $attachment->data . "\n"; + } + + # create bug + my $user = Bugzilla::User->new({ name => AUTOMATION_USER, cache => 1 }); + die "Invalid User: " . AUTOMATION_USER . "\n" unless $user; + Bugzilla->set_user($user); + my $new_bug = Bugzilla::Bug->create({ + short_desc => "[SECURITY] Bug $bug_id is no longer public", + product => $config->{product}, + component => $config->{component}, + bug_severity => 'normal', + groups => [ map { trim($_) } split(',', $config->{group}) ], + op_sys => 'Unspecified', + rep_platform => 'Unspecified', + version => $config->{version}, + cc => [ map { trim($_) } split(',', $config->{cc}) ], + comment => $comment, + }); + Bugzilla::BugMail::Send($new_bug->id, { changer => Bugzilla->user }); + Bugzilla->logout; + + $logger->info("Created bug " . $new_bug->id); } }; - if ($@) { - return (PUSH_RESULT_TRANSIENT, clean_error($@)); + my $error = $@; + Bugzilla->logout; + if ($error) { + return (PUSH_RESULT_TRANSIENT, clean_error($error)); } return PUSH_RESULT_OK; } -sub _process_attachment { - my ($self, $payload_target) = @_; - my $logger = Bugzilla->push_ext->logger; - my $attachment = blessed($payload_target) - ? $payload_target - : Bugzilla::Attachment->new({ id => $payload_target->{id}, cache => 1 }); - - if ($attachment) { - my $content = $attachment->data; - my $base_uri = quotemeta($self->config->{base_uri}); - if (my ($id) = $content =~ m|$base_uri/r/([0-9]+)|) { - my $resp = $self->client->review_request->delete($id); - my $content = $resp->decoded_content; - my $status = $resp->code; - my $result = $content && decode_json($content) ; - - if ($status == 204) { - # Success, review request deleted! - $logger->debug("Deleted review request $id"); - } - elsif ($status == 404) { - # API error 100 - Does Not Exist - $logger->debug("Does Not Exist: Review Request $id does not exist"); - } - elsif ($status == 403) { - # API error 101 - Permission Denied - $logger->error("Permission Denied: ReviewBoard Push Connector may be misconfigured"); - die $result->{err}{msg}; - } - elsif ($status == 401) { - # API error 103 - Not logged in - $logger->error("Not logged in: ReviewBoard Push Connector may be misconfigured"); - die $result->{err}{msg}; - } - else { - if ($result) { - my $code = $result->{err}{code}; - my $msg = $result->{err}{msg}; - $logger->error("Unexpected API Error: ($code) $msg"); - die $msg; - } - else { - $logger->error("Unexpected HTTP Response $status"); - die "HTTP Status: $status"; - } - } - } - else { - $logger->error("Cannot find link: ReviewBoard Push Connector may be misconfigured"); - die "Unable to find link in $content"; - } - } - else { - $logger->error("Cannot find attachment with id = $payload_target->{id}"); - } -} - -sub _process_bug { - my ($self, $payload_target) = @_; - - Bugzilla->set_user(Bugzilla::User->super_user); - my $bug = Bugzilla::Bug->new({ id => $payload_target->{id}, cache => 1 }); - my @attachments = @{ $bug->attachments }; - Bugzilla->logout; - - foreach my $attachment (@attachments) { - next if $attachment->contenttype ne RB_CONTENT_TYPE; - $self->_process_attachment($attachment); - } -} - 1; diff --git a/extensions/Push/lib/Connector/ReviewBoard/Client.pm b/extensions/Push/lib/Connector/ReviewBoard/Client.pm deleted file mode 100644 index 4848d820f..000000000 --- a/extensions/Push/lib/Connector/ReviewBoard/Client.pm +++ /dev/null @@ -1,78 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. -# -# This Source Code Form is "Incompatible With Secondary Licenses", as -# defined by the Mozilla Public License, v. 2.0. - -package Bugzilla::Extension::Push::Connector::ReviewBoard::Client; - -use 5.10.1; -use strict; -use warnings; - -use Carp qw(croak); -use LWP::UserAgent; -use Scalar::Util qw(blessed); -use URI; - -use Bugzilla::Extension::Push::Connector::ReviewBoard::ReviewRequest; - -BEGIN { - unless (LWP::UserAgent->can('delete')) { - *LWP::UserAgent::delete = sub { - my ($self, @parameters) = @_; - require HTTP::Request::Common; - my @suff = $self->_process_colonic_headers(\@parameters, 1); - return $self->request(HTTP::Request::Common::DELETE(@parameters), @suff); - }; - } -}; - -sub new { - my ($class, %params) = @_; - - croak "->new() is a class method" if blessed($class); - return bless(\%params, $class); -} - -sub username { $_[0]->{username} } -sub password { $_[0]->{password} } -sub base_uri { $_[0]->{base_uri} } -sub realm { $_[0]->{realm} // 'Web API' } -sub proxy { $_[0]->{proxy} } - -sub _netloc { - my $self = shift; - - my $uri = URI->new($self->base_uri); - return $uri->host . ':' . $uri->port; -} - -sub useragent { - my $self = shift; - - unless ($self->{useragent}) { - my $ua = LWP::UserAgent->new(agent => Bugzilla->params->{urlbase}); - $ua->credentials( - $self->_netloc, - $self->realm, - $self->username, - $self->password, - ); - $ua->proxy('https', $self->proxy) if $self->proxy; - $ua->timeout(10); - - $self->{useragent} = $ua; - } - - return $self->{useragent}; -} - -sub review_request { - my $self = shift; - - return Bugzilla::Extension::Push::Connector::ReviewBoard::ReviewRequest->new(client => $self, @_); -} - -1; diff --git a/extensions/Push/lib/Connector/ReviewBoard/Resource.pm b/extensions/Push/lib/Connector/ReviewBoard/Resource.pm deleted file mode 100644 index 3f8d434ce..000000000 --- a/extensions/Push/lib/Connector/ReviewBoard/Resource.pm +++ /dev/null @@ -1,38 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. -# -# This Source Code Form is "Incompatible With Secondary Licenses", as -# defined by the Mozilla Public License, v. 2.0. - -package Bugzilla::Extension::Push::Connector::ReviewBoard::Resource; - -use 5.10.1; -use strict; -use warnings; - -use URI; -use Carp qw(croak confess); -use Scalar::Util qw(blessed); - -sub new { - my ($class, %params) = @_; - - croak "->new() is a class method" if blessed($class); - return bless(\%params, $class); -} - -sub client { $_[0]->{client} } - -sub path { confess 'Unimplemented'; } - -sub uri { - my ($self, @path) = @_; - - my $uri = URI->new($self->client->base_uri); - $uri->path(join('/', $self->path, @path) . '/'); - - return $uri; -} - -1; diff --git a/extensions/Push/lib/Connector/ReviewBoard/ReviewRequest.pm b/extensions/Push/lib/Connector/ReviewBoard/ReviewRequest.pm deleted file mode 100644 index 32bebfbe8..000000000 --- a/extensions/Push/lib/Connector/ReviewBoard/ReviewRequest.pm +++ /dev/null @@ -1,28 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. -# -# This Source Code Form is "Incompatible With Secondary Licenses", as -# defined by the Mozilla Public License, v. 2.0. - -package Bugzilla::Extension::Push::Connector::ReviewBoard::ReviewRequest; - -use 5.10.1; -use strict; -use warnings; - -use base 'Bugzilla::Extension::Push::Connector::ReviewBoard::Resource'; - -# Reference: http://www.reviewboard.org/docs/manual/dev/webapi/2.0/resources/review-request/ - -sub path { - return '/api/review-requests'; -} - -sub delete { - my ($self, $id) = @_; - - return $self->client->useragent->delete($self->uri($id)); -} - -1; |