1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
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 qw($RealBin);
use lib ("$RealBin/..", "$RealBin/../lib", "$RealBin/../local/lib/perl5");
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 DISTINCT 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 DISTINCT 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 DISTINCT 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 DISTINCT 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
|