Create protected variable access logs POSTSEND

Why:
* The ProtectedVarsAccessLogger::logViewProtectedVariableValue
  method creates a debounced log entry for accessing protected
  variable values.
* This log can be created when a user calls the 'abuselog' query
  API. This API query is made using a GET request.
* Because the ProtectedVarsAccessLogger creates the log
  when it is called, the TransactionProfiler raises a warning
  about writing to the primary DB on a GET request.
* We should address this warning by creating the log entry on
  POSTSEND, in a similar way to how the CheckUser extension
  creates CheckUser log entries.

What:
* Wrap the call to ProtectedVarsAccessLogger::log in
  ::logViewProtectedVariableValue with a DeferredUpdate callback
  that is run POSTSEND.
** As part of this, the expectations that the code only uses the
   replica DBs are silenced inside the DeferredUpdate as the
   PostSend-GET expectations do not usually allow for writes.
   The only other method would to be create the log via a job,
   but we want the log creation to occur quickly and reliably.

Bug: T379083
Change-Id: If14e65b27b0bdd4fd0b99319024ffa281bf44656
This commit is contained in:
Dreamy Jazz 2024-11-11 14:16:00 +00:00
parent 0dd6dd636c
commit 774f4f02ef
2 changed files with 20 additions and 7 deletions

View file

@ -3,10 +3,12 @@
namespace MediaWiki\Extension\AbuseFilter;
use ManualLogEntry;
use MediaWiki\Deferred\DeferredUpdates;
use MediaWiki\MediaWikiServices;
use MediaWiki\Title\Title;
use MediaWiki\User\ActorStore;
use MediaWiki\User\UserIdentity;
use Profiler;
use Psr\Log\LoggerInterface;
use Wikimedia\Assert\Assert;
use Wikimedia\Rdbms\DBError;
@ -104,13 +106,21 @@ class ProtectedVarsAccessLogger {
if ( !$timestamp ) {
$timestamp = (int)wfTimestamp();
}
$this->log(
$performer,
$target,
self::ACTION_VIEW_PROTECTED_VARIABLE_VALUE,
true,
$timestamp
);
// Create the log on POSTSEND, as this can be called in a context of a GET request through the
// QueryAbuseLog API (T379083).
DeferredUpdates::addCallableUpdate( function () use ( $performer, $target, $timestamp ) {
// We need to create a log entry and PostSend-GET expects no writes are performed, so we need to
// silence the warnings created by this.
$trxProfiler = Profiler::instance()->getTransactionProfiler();
$scope = $trxProfiler->silenceForScope( $trxProfiler::EXPECTATION_REPLICAS_ONLY );
$this->log(
$performer,
$target,
self::ACTION_VIEW_PROTECTED_VARIABLE_VALUE,
true,
$timestamp
);
} );
}
/**

View file

@ -4,6 +4,7 @@ namespace MediaWiki\Extension\AbuseFilter\Tests\Integration;
use Generator;
use MediaWiki\CheckUser\Logging\TemporaryAccountLogger;
use MediaWiki\Deferred\DeferredUpdates;
use MediaWiki\Extension\AbuseFilter\AbuseFilterServices;
use MediaWiki\Extension\AbuseFilter\ProtectedVarsAccessLogger;
use MediaWiki\Registration\ExtensionRegistry;
@ -131,6 +132,7 @@ class ProtectedVarsAccessLoggerTest extends MediaWikiIntegrationTestCase {
AbuseFilterServices::getAbuseLoggerFactory()
->getProtectedVarsAccessLogger()
->logViewProtectedVariableValue( $performer->getUserIdentity(), '~2024-01', (int)wfTimestamp() );
DeferredUpdates::doUpdates();
// Assert that the action wasn't inserted into CheckUsers' temp account logging table
$this->assertSame(
@ -171,6 +173,7 @@ class ProtectedVarsAccessLoggerTest extends MediaWikiIntegrationTestCase {
AbuseFilterServices::getAbuseLoggerFactory()
->getProtectedVarsAccessLogger()
->logViewProtectedVariableValue( $performer->getUserIdentity(), '~2024-01', (int)wfTimestamp() );
DeferredUpdates::doUpdates();
// Assert that the action only inserted once into CheckUsers' temp account logging table
$this->assertSame(