5.7.202. Bugzilla::Extension::RedHat::Util

5.7.202.1. NAME

Bugzilla::Extension::RedHat::Util - Shared helpers for reversing the manage_user_access repudiate action.

5.7.202.2. SYNOPSIS

use Bugzilla::Extension::RedHat::Util;

my ($removed, $added) = reconstruct_repudiate_restore($bug_id, $system_id);
my ($args, $warnings) = repudiate_restore_args($bug_id, $removed, $added);
my @to_restore = find_restorable_comments($bug, $other_user_id);

Used by both Bugzilla::Extension::RedHat::Job::UndoRepudiate (which is only loaded inside the job queue worker) and extensions/RedHat/bin/undo_repudiate.pl(an admin script run outside the job queue, including for --dry-run reporting that must never disagree with what the job actually does).

reconstruct_repudiate_restore

Locates the repudiate transaction for a bug and reconstructs the pre-repudiate field values from bugs_activity.

Returns ($removed, $added) hashrefs keyed by field name, or an empty list if no matching transaction was found.

reconstruct_dup_id

Recovers a bug’s dup_id from the CMT_DUPE_OF comment Bug::set_dup_id always posts on a bug when it’s marked a duplicate (Bugzilla/Bug.pm:3405-3409) - not from bugs_activity, which never logs dup_id changes at all (see repudiate_restore_args). That comment’s type/extra_data are untouched by DeSpamComments’ text stubbing (only thetext is rewritten), so it survives a repudiate intact - the same way a CMT_ATTACHMENT_CREATED comment’s extra_datapreserves an attachment id.

Returns the dup_id, or undef if no such comment exists (e.g. the bug was marked DUPLICATE some other way that never went through set_dup_id, such as a direct SQL import).

repudiate_restore_args

Turns the ($removed, $added) hashrefs from reconstruct_repudiate_restore into the hashref shape “set_all” in Bugzilla::Bug expects.

Returns ($args, $warnings): $args is the set_all hashref: $warnings is an arrayref of human-readable strings describing anything that could not be fully restored (currently just a bug that used to be a DUPLICATE with no recoverable dup_id - see the comment below), for the caller to log/report as it sees fit. Empty when there’s nothing to flag.

restore_with_inactive_values_allowed

Bugzilla::Bug’s component/version/target_milestone/target_releasevalidators throw value_inactive when set_all tries to set a bug to a value that is no longer active for its product - which old-enough repudiated bugs run into routinely, since products retire old versions/milestones/releases over time. The value being restored isn’t a new, questionable choice; it’s simply what the bug legitimately already had.

This runs $code (typically a set_all/update call) with is_active forced true for Bugzilla::Version, Bugzilla::Component, Bugzilla::Milestone, and Bugzilla::Release, via local on each class’s typeglob - not by writing to the isactive column. Nothing outside this process’s current call stack is ever affected: no other request, job, or user can observe it, unlike flipping the column (which would make the value briefly selectable by anyone else using the same product, and could interact badly with other systems keyed off that column - exactly what happened when an earlier version of this activated-then- updated the value objects and tripped an unrelated, previously-latent bug in BayotBase’s object_end_of_update hook). The override is removed the instant $code returns, including if it dies - local restores the original sub as the call stack unwinds regardless of how it exits.

ensure_admin_can_restore_from_nobody

Spam Sinkhole’s nobody group has canedit => 1 with mandatory control, so only members of nobody may edit a bug that still carries that group, including the system_user running this restore, and even though it’s an admin. nobody is intentionally never supposed to have real direct members, so the fix is a standing group_group_map grant that makes members of admin inherit membership in nobody (the exact mechanism “create” in Bugzilla::Group uses to give admin rights over a brand new group), rather than adding anyone to nobody directly.

This is granted once and never revoked. Multiple admins can run undo_repudiate.pl concurrently for different users, restores run for a long time after the enqueuing script has already exited, and jobs run with real parallelism, so there is no point in the job/script lifecycle where it would be safe to know “no restore is still in flight” and revoke this. The grant is idempotent: safe to call every time, cheap no-op once it exists.

find_restorable_comments

Finds comments on $bug authored by $other_user_id whose current text is still the spam stub, paired with the original text recovered from longdescs_activity.

Returns a list of [$comment, $original_text] pairs.

remove_spam_tag

Removes the spam tag DeSpamComments::_insinkerator added to a comment, via raw SQL mirroring exactly how it was added (in reverse) - including the matching longdescs_tags_activity row, so the removal is itself audited.

Bugzilla::Comment::remove_tag/update() is not used here: in production, restoring a comment’s text worked but the tag it added (_insinkerator writes it via raw SQL) was still left in place afterwards even though remove_tag/update() ran with no error. Going straight at longdescs_tags with the same primitives _insinkerator used to add the tag sidesteps whatever in the Comment object/tag-diffing machinery was responsible, rather than continuing to rely on a path already shown not to work for this exact tag.


This documentation undoubtedly has bugs; if you find some, please file them here.