diff options
-rwxr-xr-x | scripts/security_remove.pl | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/scripts/security_remove.pl b/scripts/security_remove.pl new file mode 100755 index 000000000..90099e387 --- /dev/null +++ b/scripts/security_remove.pl @@ -0,0 +1,189 @@ +#!/usr/bin/perl +# 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. + +use 5.10.1; +use strict; +use warnings; + +use FindBin '$RealBin'; +use lib "$RealBin/../..", "$RealBin/../../lib"; + +use Bugzilla; +use Bugzilla::Constants; +use Bugzilla::Field; +use Bugzilla::User; + +use Pod::Usage; + +# Load extensions for monkeypatched $user->clear_last_statistics_ts() +BEGIN { Bugzilla->extensions(); } + +Bugzilla->usage_mode(USAGE_MODE_CMDLINE); + +if (scalar @ARGV < 1) { + die <<USAGE; +Usage: security_remove.pl <user> + +E.g.: security_remove.pl foo\@bar.com + +will remove the specified user from the following roles on private only bugs: + +- Set reporter_accessible to false if user is the reporter +- Remove from the cc list +- Clear qa_contact if the user is qa_contact +- Re-assign to nobody\@mozilla.org if user is the assignee + +This script should not touch user's membership or default assignee, qa contact, +or cc settings for components. + +Script should not send any email about the changes. +USAGE +} + +my ($login_name) = @ARGV; + +# Load nobody user and set as current +my $auto_user = Bugzilla::User->check({ name => 'automation@bmo.tld' }); +Bugzilla->set_user($auto_user); + +# Check target user +my $target_user = Bugzilla::User->check({ name => $login_name }); + +my $dbh = Bugzilla->dbh; +my $timestamp = $dbh->selectrow_array('SELECT LOCALTIMESTAMP(0)'); + +# Gather bug ids +my $reporter_bugs = $dbh->selectcol_arrayref( + q{SELECT bugs.bug_id + FROM bugs, bug_group_map + WHERE bugs.bug_id = bug_group_map.bug_id + AND bugs.reporter_accessible = 1 + AND bugs.reporter = ?}, + undef, $target_user->id) || []; + +my $assignee_bugs = $dbh->selectcol_arrayref( + q{SELECT bugs.bug_id + FROM bugs, bug_group_map + WHERE bugs.bug_id = bug_group_map.bug_id + AND bugs.assigned_to = ?}, + undef, $target_user->id) || []; + +my $qa_bugs = $dbh->selectcol_arrayref( + q{SELECT bugs.bug_id + FROM bugs, bug_group_map + WHERE bugs.bug_id = bug_group_map.bug_id + AND bugs.qa_contact = ?}, + undef, $target_user->id) || []; + +my $cc_bugs = $dbh->selectcol_arrayref( + q{SELECT cc.bug_id + FROM cc, bug_group_map + WHERE cc.bug_id = bug_group_map.bug_id + AND cc.who = ?}, + undef, $target_user->id) || []; + +my $reporter_count = scalar @$reporter_bugs; +my $assignee_count = scalar @$assignee_bugs; +my $qa_count = scalar @$qa_bugs; +my $cc_count = scalar @$cc_bugs; + +if (!$reporter_count + && !$assignee_count + && !$qa_count + && !$cc_count) +{ + warn "There are no bugs to update.\n"; + exit 1; +} + +warn <<EOF; +About to remove user from the following number of bugs: + +Reporter: $reporter_count +Assignee: $assignee_count +QA Contact: $qa_count +CC: $cc_count + +Press <Ctrl-C> to stop or <Enter> to continue... +EOF +getc(); + +$dbh->bz_start_transaction; + +# Reporter - set reporter_accessible to false +my $field_id = get_field_id('reporter_accessible'); +foreach my $bug_id (@$reporter_bugs) { + warn "Updating bug $bug_id\n"; + $dbh->do( + q{INSERT INTO bugs_activity (bug_id, who, bug_when, fieldid, removed, added) + VALUES (?, ?, ?, ?, ?, ?)}, + undef, $bug_id, $auto_user->id, $timestamp, $field_id, 1, 0); + $dbh->do( + q{UPDATE bugs SET reporter_accessible = 0, delta_ts = ?, lastdiffed = ? + WHERE bug_id = ?}, + undef, $timestamp, $timestamp, $bug_id); +} + +# Assignee +$field_id = get_field_id('assigned_to'); +foreach my $bug_id (@$assignee_bugs) { + warn "Updating bug $bug_id\n"; + $dbh->do( + q{INSERT INTO bugs_activity (bug_id, who, bug_when, fieldid, removed, added) + VALUES (?, ?, ?, ?, ?, ?)}, + undef, $bug_id, $auto_user->id, $timestamp, $field_id, + $target_user->login, $auto_user->login); + $dbh->do( + q{UPDATE bugs SET assigned_to = ?, delta_ts = ?, lastdiffed = ? + WHERE bug_id = ?}, + undef, $auto_user->id, $timestamp, $timestamp, $bug_id); +} + +# QA Contact +$field_id = get_field_id('qa_contact'); +foreach my $bug_id (@$qa_bugs) { + warn "Updating bug $bug_id\n"; + $dbh->do( + q{INSERT INTO bugs_activity (bug_id, who, bug_when, fieldid, removed, added) + VALUES (?, ?, ?, ?, ?, '')}, + undef, $bug_id, $auto_user->id, $timestamp, $field_id, $target_user->login); + $dbh->do( + q{UPDATE bugs SET qa_contact = NULL, delta_ts = ?, lastdiffed = ? + WHERE bug_id = ?}, + undef, $timestamp, $timestamp, $bug_id); +} + +# CC list +$field_id = get_field_id('cc'); +foreach my $bug_id (@$cc_bugs) { + warn "Updating bug $bug_id\n"; + $dbh->do( + q{INSERT INTO bugs_activity (bug_id, who, bug_when, fieldid, removed, added) + VALUES (?, ?, ?, ?, ?, '')}, + undef, $bug_id, $auto_user->id, $timestamp, $field_id, $target_user->login); + $dbh->do(q{DELETE FROM cc WHERE bug_id = ? AND who = ?}, + undef, $bug_id, $target_user->id); +} + +$target_user->clear_last_statistics_ts(); + +$dbh->bz_commit_transaction; + +# It's complex to determine which items now need to be flushed from memcached. +# As this is expected to be a rare event, we just flush the entire cache. +Bugzilla->memcached->clear_all(); + +__END__ + +=head1 NAME + +security_remove.pl - Remove user from any role associated with private bugs. + +=head1 SYNOPSIS + + security_remove.pl foo@bar.com |