-
Notifications
You must be signed in to change notification settings - Fork 11
Add configurable action protection via $wgCrawlerProtectedActions #14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -94,6 +94,9 @@ class MediaWikiServices { | |
| /** @var bool Control CrawlerProtectionUse418 config for testing */ | ||
| public static $testUse418 = false; | ||
|
|
||
| /** @var array|null Control CrawlerProtectedActions config for testing */ | ||
| public static $testProtectedActions = null; | ||
|
|
||
| /** | ||
| * @return MediaWikiServices | ||
| */ | ||
|
|
@@ -130,6 +133,11 @@ public function getMainConfig() { | |
| * @return mixed | ||
| */ | ||
| public function get( $name ) { | ||
| if ( $name === 'CrawlerProtectedActions' ) { | ||
| return MediaWikiServices::$testProtectedActions !== null | ||
| ? MediaWikiServices::$testProtectedActions | ||
| : [ 'history' ]; | ||
| } | ||
|
Comment on lines
+136
to
+140
|
||
| if ( $name === 'CrawlerProtectedSpecialPages' ) { | ||
| return [ | ||
| 'RecentChangesLinked', | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -69,10 +69,13 @@ public static function setUpBeforeClass(): void { | |||||||||||||
| */ | ||||||||||||||
| protected function tearDown(): void { | ||||||||||||||
| parent::tearDown(); | ||||||||||||||
| // Reset the test config flag (only exists in stub environment) | ||||||||||||||
| // Reset the test config flags (only exists in stub environment) | ||||||||||||||
| if ( property_exists( '\MediaWiki\MediaWikiServices', 'testUse418' ) ) { | ||||||||||||||
| \MediaWiki\MediaWikiServices::$testUse418 = false; | ||||||||||||||
| } | ||||||||||||||
| if ( property_exists( '\MediaWiki\MediaWikiServices', 'testProtectedActions' ) ) { | ||||||||||||||
| \MediaWiki\MediaWikiServices::$testProtectedActions = null; | ||||||||||||||
| } | ||||||||||||||
| // Only reset if the method exists (in our test stubs) | ||||||||||||||
| if ( method_exists( '\MediaWiki\MediaWikiServices', 'resetForTesting' ) ) { | ||||||||||||||
| \MediaWiki\MediaWikiServices::resetForTesting(); | ||||||||||||||
|
|
@@ -160,6 +163,240 @@ public function testNonRevisionTypeAlwaysAllowed() { | |||||||||||||
| $this->assertTrue( $result ); | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| /** | ||||||||||||||
| * @covers ::onMediaWikiPerformAction | ||||||||||||||
| */ | ||||||||||||||
| public function testHistoryActionBlocksAnonymous() { | ||||||||||||||
| $output = $this->createMock( self::$outputPageClassName ); | ||||||||||||||
|
|
||||||||||||||
| $request = $this->createMock( self::$webRequestClassName ); | ||||||||||||||
| $request->method( 'getVal' )->willReturnCallback( static function ( $key, $default = null ) { | ||||||||||||||
| if ( $key === 'action' ) { | ||||||||||||||
| return 'history'; | ||||||||||||||
| } | ||||||||||||||
| return $default; | ||||||||||||||
| } ); | ||||||||||||||
|
|
||||||||||||||
| $user = $this->createMock( self::$userClassName ); | ||||||||||||||
| $user->method( 'isRegistered' )->willReturn( false ); | ||||||||||||||
|
|
||||||||||||||
| $article = $this->createMock( self::$articleClassName ); | ||||||||||||||
| $title = $this->createMock( self::$titleClassName ); | ||||||||||||||
| $wiki = $this->createMock( self::$actionEntryPointClassName ); | ||||||||||||||
|
|
||||||||||||||
| $runner = $this->getMockBuilder( Hooks::class ) | ||||||||||||||
| ->onlyMethods( [ 'denyAccess' ] ) | ||||||||||||||
| ->getMock(); | ||||||||||||||
| $runner->expects( $this->once() )->method( 'denyAccess' ); | ||||||||||||||
|
|
||||||||||||||
| $result = $runner->onMediaWikiPerformAction( $output, $article, $title, $user, $request, $wiki ); | ||||||||||||||
| $this->assertFalse( $result ); | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| /** | ||||||||||||||
| * @covers ::onMediaWikiPerformAction | ||||||||||||||
| */ | ||||||||||||||
| public function testHistoryActionAllowsLoggedIn() { | ||||||||||||||
| $output = $this->createMock( self::$outputPageClassName ); | ||||||||||||||
|
|
||||||||||||||
| $request = $this->createMock( self::$webRequestClassName ); | ||||||||||||||
| $request->method( 'getVal' )->willReturnCallback( static function ( $key, $default = null ) { | ||||||||||||||
| if ( $key === 'action' ) { | ||||||||||||||
| return 'history'; | ||||||||||||||
| } | ||||||||||||||
| return $default; | ||||||||||||||
| } ); | ||||||||||||||
|
|
||||||||||||||
| $user = $this->createMock( self::$userClassName ); | ||||||||||||||
| $user->method( 'isRegistered' )->willReturn( true ); | ||||||||||||||
|
|
||||||||||||||
| $article = $this->createMock( self::$articleClassName ); | ||||||||||||||
| $title = $this->createMock( self::$titleClassName ); | ||||||||||||||
| $wiki = $this->createMock( self::$actionEntryPointClassName ); | ||||||||||||||
|
|
||||||||||||||
| $runner = $this->getMockBuilder( Hooks::class ) | ||||||||||||||
| ->onlyMethods( [ 'denyAccess' ] ) | ||||||||||||||
| ->getMock(); | ||||||||||||||
| $runner->expects( $this->never() )->method( 'denyAccess' ); | ||||||||||||||
|
|
||||||||||||||
| $result = $runner->onMediaWikiPerformAction( $output, $article, $title, $user, $request, $wiki ); | ||||||||||||||
| $this->assertTrue( $result ); | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| /** | ||||||||||||||
| * @covers ::onMediaWikiPerformAction | ||||||||||||||
| */ | ||||||||||||||
| public function testEmptyProtectedActionsAllowsHistory() { | ||||||||||||||
| // Skip this test in MediaWiki environment - it requires service container | ||||||||||||||
| if ( !property_exists( '\MediaWiki\MediaWikiServices', 'testProtectedActions' ) ) { | ||||||||||||||
| $this->markTestSkipped( | ||||||||||||||
| 'Test requires stub MediaWikiServices with testProtectedActions. Skipped in MediaWiki environment.' | ||||||||||||||
| ); | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
|
Comment on lines
+230
to
+236
|
||||||||||||||
| // Skip this test in MediaWiki environment - it requires service container | |
| if ( !property_exists( '\MediaWiki\MediaWikiServices', 'testUse418' ) ) { | |
| $this->markTestSkipped( | |
| 'Test requires stub MediaWikiServices. Skipped in MediaWiki unit test environment.' | |
| ); | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CrawlerProtectedActionsis now configurable, but there are no tests covering non-default configuration values (e.g. empty array allowingaction=history, or protecting an additional action). Adding such cases would ensure the new config wiring is actually exercised and remains stable across MediaWiki versions.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot apply changes based on this feedback
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Applied all feedback changes in commit 91c86bc:
getVal()mocks to usewillReturnCallbackfor proper single-argument matchingMediaWikiServices::$testProtectedActionsstatic propertytestEmptyProtectedActionsAllowsHistory- verifies empty array allows historytestCustomProtectedActionBlocks- verifies custom actions are blockedtestCustomProtectedActionAllowsOtherActions- verifies non-configured actions are allowedAll 26 tests pass and code follows MediaWiki standards.