From 019c6a02d3ee89081424192de908d292bf58dc2f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 18 May 2026 20:33:14 +0000 Subject: [PATCH 1/7] Initial plan From 6626f2ce8aa133166f0c4dfe6d612f230830b6e4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 18 May 2026 20:45:28 +0000 Subject: [PATCH 2/7] Tie history-related blocks to 'history' protected action config Agent-Logs-Url: https://github.com/mywikis/CrawlerProtection/sessions/74ca4e87-8423-400c-9cd2-dcbbcecf61c6 Co-authored-by: jeffw16 <11380894+jeffw16@users.noreply.github.com> --- includes/CrawlerProtectionService.php | 17 +++- tests/phpunit/namespaced-stubs.php | 6 +- .../unit/CrawlerProtectionServiceTest.php | 77 +++++++++++++++++++ 3 files changed, 95 insertions(+), 5 deletions(-) diff --git a/includes/CrawlerProtectionService.php b/includes/CrawlerProtectionService.php index 3df4426..0dd0360 100644 --- a/includes/CrawlerProtectionService.php +++ b/includes/CrawlerProtectionService.php @@ -90,11 +90,20 @@ public function checkPerformAction( $diffId = (int)$request->getVal( 'diff' ); $oldId = (int)$request->getVal( 'oldid' ); + // The type=revision, diff and oldid parameters are all ways of + // viewing page history. They are only blocked when 'history' is + // in the configured list of protected actions, so that operators + // can fully disable history blocking by removing 'history' from + // $wgCrawlerProtectedActions. + $historyProtected = $this->isProtectedAction( 'history' ); + if ( - $type === 'revision' - || $this->isProtectedAction( $action ) - || $diffId > 0 - || $oldId > 0 + $this->isProtectedAction( $action ) + || ( $historyProtected && ( + $type === 'revision' + || $diffId > 0 + || $oldId > 0 + ) ) ) { $this->responseFactory->denyAccess( $output ); return false; diff --git a/tests/phpunit/namespaced-stubs.php b/tests/phpunit/namespaced-stubs.php index eff675a..b173c54 100644 --- a/tests/phpunit/namespaced-stubs.php +++ b/tests/phpunit/namespaced-stubs.php @@ -100,9 +100,13 @@ public function getContext() { namespace MediaWiki\User { class User { - public function isRegistered() { + public function isRegistered(): bool { return false; } + + public function getName(): string { + return ''; + } } } diff --git a/tests/phpunit/unit/CrawlerProtectionServiceTest.php b/tests/phpunit/unit/CrawlerProtectionServiceTest.php index 9349363..8d99287 100644 --- a/tests/phpunit/unit/CrawlerProtectionServiceTest.php +++ b/tests/phpunit/unit/CrawlerProtectionServiceTest.php @@ -204,6 +204,83 @@ public function testCheckPerformActionBlocksConfiguredAction() { $this->assertFalse( $service->checkPerformAction( $output, $user, $request ) ); } + /** + * When 'history' is removed from CrawlerProtectedActions, the + * history-related parameters (type=revision, diff, oldid) should + * also be allowed, so that operators can fully disable history + * blocking via configuration (see issue: history can't be unblocked). + * + * @covers ::checkPerformAction + * @dataProvider provideHistoryRelatedRequestParams + * + * @param array $getValMap + * @param string $msg + */ + public function testCheckPerformActionAllowsHistoryRelatedWhenNotConfigured( + array $getValMap, string $msg + ) { + $output = $this->createMock( self::$outputPageClassName ); + $user = $this->createMock( self::$userClassName ); + $user->method( 'isRegistered' )->willReturn( false ); + $user->method( 'getName' )->willReturn( '127.0.0.1' ); + + $request = $this->createMock( self::$webRequestClassName ); + $request->method( 'getVal' )->willReturnMap( $getValMap ); + + $responseFactory = $this->createMock( ResponseFactory::class ); + $responseFactory->expects( $this->never() )->method( 'denyAccess' ); + + $service = $this->buildService( [], [], [], $responseFactory ); + $this->assertTrue( $service->checkPerformAction( $output, $user, $request ), $msg ); + } + + /** + * Data provider for history-related parameters that should be + * allowed when 'history' is not in CrawlerProtectedActions. + * + * @return array + */ + public function provideHistoryRelatedRequestParams(): array { + return [ + 'action=history' => [ + [ + [ 'type', null, null ], + [ 'action', null, 'history' ], + [ 'diff', null, null ], + [ 'oldid', null, null ], + ], + 'action=history should be allowed when history not protected', + ], + 'type=revision' => [ + [ + [ 'type', null, 'revision' ], + [ 'action', null, null ], + [ 'diff', null, null ], + [ 'oldid', null, null ], + ], + 'type=revision should be allowed when history not protected', + ], + 'diff=42' => [ + [ + [ 'type', null, null ], + [ 'action', null, null ], + [ 'diff', null, '42' ], + [ 'oldid', null, null ], + ], + 'diff=42 should be allowed when history not protected', + ], + 'oldid=99' => [ + [ + [ 'type', null, null ], + [ 'action', null, null ], + [ 'diff', null, null ], + [ 'oldid', null, '99' ], + ], + 'oldid=99 should be allowed when history not protected', + ], + ]; + } + /** * @covers ::checkPerformAction */ From 617e5268ef47b3806fd671c6466922c196c02f70 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 18 Jun 2026 19:01:53 +0000 Subject: [PATCH 3/7] Use provide_default merge strategy so emptying config arrays works --- extension.json | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/extension.json b/extension.json index d2486d0..4ce8c2c 100644 --- a/extension.json +++ b/extension.json @@ -27,14 +27,16 @@ "CrawlerProtectedActions": { "value": [ "history" - ] + ], + "merge_strategy": "provide_default" }, "CrawlerProtectedSpecialPages": { "value": [ "mobilediff", "recentchangeslinked", "whatlinkshere" - ] + ], + "merge_strategy": "provide_default" }, "CrawlerProtectionRawDenial": { "value": false @@ -49,7 +51,8 @@ "value": "403 Forbidden. You must be logged in to view this page." }, "CrawlerProtectionAllowedIPs": { - "value": [] + "value": [], + "merge_strategy": "provide_default" } }, "ServiceWiringFiles": [ From be8afbe1c85a695bd699c2c4547bf17bee4398b0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 18 Jun 2026 20:07:29 +0000 Subject: [PATCH 4/7] CI: disable composer advisory blocking so MW 1.39 deps install --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 274526a..2162710 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -51,7 +51,7 @@ jobs: - name: Setup Composer # Don't block insecure packages because MediaWiki might be using outdated dependencies, which shouldn't block the extension's pipelines from running run: | - echo '{"extra":{"merge-plugin":{"include":["extensions/*/composer.json","skins/*/composer.json"]}},"config":{"audit":{"abandoned":"report","block-insecure":false}}}' > composer.local.json + echo '{"extra":{"merge-plugin":{"include":["extensions/*/composer.json","skins/*/composer.json"]}},"config":{"audit":{"abandoned":"report"},"policy":{"advisories":{"block":false}}}}' > composer.local.json composer update composer update - name: Lint @@ -96,7 +96,7 @@ jobs: - name: Setup Composer # Don't block insecure packages because MediaWiki might be using outdated dependencies, which shouldn't block the extension's pipelines from running run: | - echo '{"extra":{"merge-plugin":{"include":["extensions/*/composer.json","skins/*/composer.json"]}},"config":{"audit":{"abandoned":"report","block-insecure":false}}}' > composer.local.json + echo '{"extra":{"merge-plugin":{"include":["extensions/*/composer.json","skins/*/composer.json"]}},"config":{"audit":{"abandoned":"report"},"policy":{"advisories":{"block":false}}}}' > composer.local.json composer update composer update - name: Phan @@ -137,7 +137,7 @@ jobs: - name: Setup Composer # Don't block insecure packages because MediaWiki might be using outdated dependencies, which shouldn't block the extension's pipelines from running run: | - echo '{"extra":{"merge-plugin":{"include":["extensions/*/composer.json","skins/*/composer.json"]}},"config":{"audit":{"abandoned":"report","block-insecure":false}}}' > composer.local.json + echo '{"extra":{"merge-plugin":{"include":["extensions/*/composer.json","skins/*/composer.json"]}},"config":{"audit":{"abandoned":"report"},"policy":{"advisories":{"block":false}}}}' > composer.local.json composer update composer update - name: Install MediaWiki From 2068c23b4a0e409b92caebea346f97890be3bb29 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 18 Jun 2026 22:57:11 +0000 Subject: [PATCH 5/7] CI: set composer advisory policy on root composer.json for MW 1.39 --- .github/workflows/ci.yml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2162710..6c26d23 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -51,7 +51,9 @@ jobs: - name: Setup Composer # Don't block insecure packages because MediaWiki might be using outdated dependencies, which shouldn't block the extension's pipelines from running run: | - echo '{"extra":{"merge-plugin":{"include":["extensions/*/composer.json","skins/*/composer.json"]}},"config":{"audit":{"abandoned":"report"},"policy":{"advisories":{"block":false}}}}' > composer.local.json + echo '{"extra":{"merge-plugin":{"include":["extensions/*/composer.json","skins/*/composer.json"]}}}' > composer.local.json + # composer-merge-plugin does not merge the "config" section from composer.local.json, so set the advisory policy on the root composer.json directly + composer config --no-plugins policy.advisories.block false composer update composer update - name: Lint @@ -96,7 +98,9 @@ jobs: - name: Setup Composer # Don't block insecure packages because MediaWiki might be using outdated dependencies, which shouldn't block the extension's pipelines from running run: | - echo '{"extra":{"merge-plugin":{"include":["extensions/*/composer.json","skins/*/composer.json"]}},"config":{"audit":{"abandoned":"report"},"policy":{"advisories":{"block":false}}}}' > composer.local.json + echo '{"extra":{"merge-plugin":{"include":["extensions/*/composer.json","skins/*/composer.json"]}}}' > composer.local.json + # composer-merge-plugin does not merge the "config" section from composer.local.json, so set the advisory policy on the root composer.json directly + composer config --no-plugins policy.advisories.block false composer update composer update - name: Phan @@ -137,7 +141,9 @@ jobs: - name: Setup Composer # Don't block insecure packages because MediaWiki might be using outdated dependencies, which shouldn't block the extension's pipelines from running run: | - echo '{"extra":{"merge-plugin":{"include":["extensions/*/composer.json","skins/*/composer.json"]}},"config":{"audit":{"abandoned":"report"},"policy":{"advisories":{"block":false}}}}' > composer.local.json + echo '{"extra":{"merge-plugin":{"include":["extensions/*/composer.json","skins/*/composer.json"]}}}' > composer.local.json + # composer-merge-plugin does not merge the "config" section from composer.local.json, so set the advisory policy on the root composer.json directly + composer config --no-plugins policy.advisories.block false composer update composer update - name: Install MediaWiki From a18122006a8a5f04c2f9b9de3b6e100e61d85458 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Thu, 18 Jun 2026 20:35:49 -0700 Subject: [PATCH 6/7] Address feedback: add `$wgCrawlerProtectionProtectRevisions` to independently control revision/diff blocking (#32) * Initial plan * Add CrawlerProtectionProtectRevisions to independently control revision/diff blocking --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> --- README.md | 11 ++ extension.json | 3 + includes/CrawlerProtectionService.php | 15 +- .../unit/CrawlerProtectionServiceTest.php | 147 +++++++++++++++++- 4 files changed, 162 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 27dbe91..703544e 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,17 @@ intensive. `curl -s "[YOURWIKI]api.php?action=query&meta=siteinfo&siprop=specialpagealiases&format=json" | jq -r '.query.specialpagealiases[].aliases[]' | sort` Of course certain Specials MUST be allowed like Special:Login so do not block everything. +* `$wgCrawlerProtectedActions` - array of MediaWiki action names to block for + anonymous users (default: `[ 'history' ]`). Removing `'history'` from this + list disables protection of the history-listing page but does not affect + whether individual revisions and diffs are protected (see + `$wgCrawlerProtectionProtectRevisions` below). +* `$wgCrawlerProtectionProtectRevisions` - when `true` (default), anonymous + access to individual revisions and diffs (requests using `type=revision`, + `diff=`, or `oldid=` query parameters) is denied. Set to `false` to allow + anonymous access to those URLs. This setting is independent of + `$wgCrawlerProtectedActions`, so you can protect revisions/diffs without + protecting the history listing page, or vice versa. * `$wgCrawlerProtectionUse418` - drop denied requests in a quick way via `die();` with [418 I'm a teapot](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/418) diff --git a/extension.json b/extension.json index 4ce8c2c..4b41a6a 100644 --- a/extension.json +++ b/extension.json @@ -53,6 +53,9 @@ "CrawlerProtectionAllowedIPs": { "value": [], "merge_strategy": "provide_default" + }, + "CrawlerProtectionProtectRevisions": { + "value": true } }, "ServiceWiringFiles": [ diff --git a/includes/CrawlerProtectionService.php b/includes/CrawlerProtectionService.php index 0dd0360..fb00df6 100644 --- a/includes/CrawlerProtectionService.php +++ b/includes/CrawlerProtectionService.php @@ -44,6 +44,7 @@ class CrawlerProtectionService { 'CrawlerProtectedActions', 'CrawlerProtectedSpecialPages', 'CrawlerProtectionAllowedIPs', + 'CrawlerProtectionProtectRevisions', ]; /** @var ServiceOptions */ @@ -90,16 +91,16 @@ public function checkPerformAction( $diffId = (int)$request->getVal( 'diff' ); $oldId = (int)$request->getVal( 'oldid' ); - // The type=revision, diff and oldid parameters are all ways of - // viewing page history. They are only blocked when 'history' is - // in the configured list of protected actions, so that operators - // can fully disable history blocking by removing 'history' from - // $wgCrawlerProtectedActions. - $historyProtected = $this->isProtectedAction( 'history' ); + // $wgCrawlerProtectionProtectRevisions independently controls whether + // type=revision, diff and oldid requests are blocked. This allows + // operators to disable history-listing protection (by removing 'history' + // from $wgCrawlerProtectedActions) while still blocking direct access + // to individual revisions and diffs, or vice versa. + $revisionsProtected = $this->options->get( 'CrawlerProtectionProtectRevisions' ); if ( $this->isProtectedAction( $action ) - || ( $historyProtected && ( + || ( $revisionsProtected && ( $type === 'revision' || $diffId > 0 || $oldId > 0 diff --git a/tests/phpunit/unit/CrawlerProtectionServiceTest.php b/tests/phpunit/unit/CrawlerProtectionServiceTest.php index 8d99287..172470d 100644 --- a/tests/phpunit/unit/CrawlerProtectionServiceTest.php +++ b/tests/phpunit/unit/CrawlerProtectionServiceTest.php @@ -44,20 +44,23 @@ public static function setUpBeforeClass(): void { * @param array $protectedActions * @param string|array $allowedIPs * @param ResponseFactory|\PHPUnit\Framework\MockObject\MockObject|null $responseFactory + * @param bool $protectRevisions * @return CrawlerProtectionService */ private function buildService( array $protectedPages = [ 'recentchangeslinked', 'whatlinkshere', 'mobilediff' ], array $protectedActions = [ 'history' ], $allowedIPs = [], - $responseFactory = null + $responseFactory = null, + bool $protectRevisions = true ): CrawlerProtectionService { $options = new ServiceOptions( CrawlerProtectionService::CONSTRUCTOR_OPTIONS, [ 'CrawlerProtectedActions' => $protectedActions, 'CrawlerProtectedSpecialPages' => $protectedPages, - 'CrawlerProtectionAllowedIPs' => $allowedIPs + 'CrawlerProtectionAllowedIPs' => $allowedIPs, + 'CrawlerProtectionProtectRevisions' => $protectRevisions, ] ); @@ -205,10 +208,11 @@ public function testCheckPerformActionBlocksConfiguredAction() { } /** - * When 'history' is removed from CrawlerProtectedActions, the - * history-related parameters (type=revision, diff, oldid) should - * also be allowed, so that operators can fully disable history - * blocking via configuration (see issue: history can't be unblocked). + * When 'history' is removed from CrawlerProtectedActions, action=history + * should be allowed. When CrawlerProtectionProtectRevisions is false, + * the history-related parameters (type=revision, diff, oldid) should also + * be allowed, so that operators can independently control revision and + * history-listing protection. * * @covers ::checkPerformAction * @dataProvider provideHistoryRelatedRequestParams @@ -230,7 +234,7 @@ public function testCheckPerformActionAllowsHistoryRelatedWhenNotConfigured( $responseFactory = $this->createMock( ResponseFactory::class ); $responseFactory->expects( $this->never() )->method( 'denyAccess' ); - $service = $this->buildService( [], [], [], $responseFactory ); + $service = $this->buildService( [], [], [], $responseFactory, false ); $this->assertTrue( $service->checkPerformAction( $output, $user, $request ), $msg ); } @@ -304,6 +308,135 @@ public function testCheckPerformActionAllowsActionNotInConfig() { $this->assertTrue( $service->checkPerformAction( $output, $user, $request ) ); } + /** + * When CrawlerProtectionProtectRevisions is true and 'history' is NOT in + * CrawlerProtectedActions, revision/diff requests should still be blocked. + * This allows operators to protect individual revisions without protecting + * the history listing page. + * + * @covers ::checkPerformAction + * @dataProvider provideRevisionOnlyRequestParams + * + * @param array $getValMap + * @param string $msg + */ + public function testCheckPerformActionBlocksRevisionsWhenProtectRevisionsTrueHistoryUnconfigured( + array $getValMap, string $msg + ) { + $output = $this->createMock( self::$outputPageClassName ); + $user = $this->createMock( self::$userClassName ); + $user->method( 'isRegistered' )->willReturn( false ); + $user->method( 'getName' )->willReturn( '127.0.0.1' ); + + $request = $this->createMock( self::$webRequestClassName ); + $request->method( 'getVal' )->willReturnMap( $getValMap ); + + $responseFactory = $this->createMock( ResponseFactory::class ); + $responseFactory->expects( $this->once() )->method( 'denyAccess' )->with( $output ); + + // history not in protected actions, but protectRevisions = true + $service = $this->buildService( [], [], [], $responseFactory, true ); + $this->assertFalse( $service->checkPerformAction( $output, $user, $request ), $msg ); + } + + /** + * Data provider for revision/diff request parameters (excludes action=history + * since that is controlled independently by CrawlerProtectedActions). + * + * @return array + */ + public function provideRevisionOnlyRequestParams(): array { + return [ + 'type=revision' => [ + [ + [ 'type', null, 'revision' ], + [ 'action', null, null ], + [ 'diff', null, null ], + [ 'oldid', null, null ], + ], + 'type=revision should be blocked when CrawlerProtectionProtectRevisions is true', + ], + 'diff=42' => [ + [ + [ 'type', null, null ], + [ 'action', null, null ], + [ 'diff', null, '42' ], + [ 'oldid', null, null ], + ], + 'diff=42 should be blocked when CrawlerProtectionProtectRevisions is true', + ], + 'oldid=99' => [ + [ + [ 'type', null, null ], + [ 'action', null, null ], + [ 'diff', null, null ], + [ 'oldid', null, '99' ], + ], + 'oldid=99 should be blocked when CrawlerProtectionProtectRevisions is true', + ], + ]; + } + + /** + * When CrawlerProtectionProtectRevisions is false, revision/diff requests + * should be allowed even when 'history' is in CrawlerProtectedActions. + * + * @covers ::checkPerformAction + * @dataProvider provideRevisionOnlyRequestParams + * + * @param array $getValMap + * @param string $msg + */ + public function testCheckPerformActionAllowsRevisionsWhenProtectRevisionsFalse( + array $getValMap, string $msg + ) { + $output = $this->createMock( self::$outputPageClassName ); + $user = $this->createMock( self::$userClassName ); + $user->method( 'isRegistered' )->willReturn( false ); + $user->method( 'getName' )->willReturn( '127.0.0.1' ); + + $request = $this->createMock( self::$webRequestClassName ); + $request->method( 'getVal' )->willReturnMap( $getValMap ); + + $responseFactory = $this->createMock( ResponseFactory::class ); + $responseFactory->expects( $this->never() )->method( 'denyAccess' ); + + // history is protected, but protectRevisions = false + $service = $this->buildService( [], [ 'history' ], [], $responseFactory, false ); + $this->assertTrue( + $service->checkPerformAction( $output, $user, $request ), + $msg + ); + } + + /** + * action=history is controlled solely by CrawlerProtectedActions. It must + * remain blocked even when CrawlerProtectionProtectRevisions is false. + * + * @covers ::checkPerformAction + */ + public function testCheckPerformActionBlocksHistoryListingEvenWhenProtectRevisionsFalse() { + $output = $this->createMock( self::$outputPageClassName ); + $user = $this->createMock( self::$userClassName ); + $user->method( 'isRegistered' )->willReturn( false ); + $user->method( 'getName' )->willReturn( '127.0.0.1' ); + + $request = $this->createMock( self::$webRequestClassName ); + $request->method( 'getVal' )->willReturnMap( [ + [ 'type', null, null ], + [ 'action', null, 'history' ], + [ 'diff', null, null ], + [ 'oldid', null, null ], + ] ); + + $responseFactory = $this->createMock( ResponseFactory::class ); + $responseFactory->expects( $this->once() )->method( 'denyAccess' )->with( $output ); + + // history is protected, but protectRevisions = false + $service = $this->buildService( [], [ 'history' ], [], $responseFactory, false ); + $this->assertFalse( $service->checkPerformAction( $output, $user, $request ) ); + } + // --------------------------------------------------------------- // isProtectedAction tests // --------------------------------------------------------------- From 80e1fdad68e86ff03637f27a5feac6b5397896f2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 19 Jun 2026 03:45:03 +0000 Subject: [PATCH 7/7] tests: de-duplicate history/revision allow-cases now that they are decoupled --- .../unit/CrawlerProtectionServiceTest.php | 60 ++----------------- 1 file changed, 6 insertions(+), 54 deletions(-) diff --git a/tests/phpunit/unit/CrawlerProtectionServiceTest.php b/tests/phpunit/unit/CrawlerProtectionServiceTest.php index 172470d..d3e7acf 100644 --- a/tests/phpunit/unit/CrawlerProtectionServiceTest.php +++ b/tests/phpunit/unit/CrawlerProtectionServiceTest.php @@ -208,19 +208,18 @@ public function testCheckPerformActionBlocksConfiguredAction() { } /** - * When 'history' is removed from CrawlerProtectedActions, action=history - * should be allowed. When CrawlerProtectionProtectRevisions is false, - * the history-related parameters (type=revision, diff, oldid) should also - * be allowed, so that operators can independently control revision and - * history-listing protection. + * When CrawlerProtectionProtectRevisions is false and 'history' is not in + * CrawlerProtectedActions, the revision-shaped parameters (type=revision, + * diff, oldid) should be allowed. The action=history allowed-case is + * covered separately by testCheckPerformActionAllowsActionNotInConfig(). * * @covers ::checkPerformAction - * @dataProvider provideHistoryRelatedRequestParams + * @dataProvider provideRevisionOnlyRequestParams * * @param array $getValMap * @param string $msg */ - public function testCheckPerformActionAllowsHistoryRelatedWhenNotConfigured( + public function testCheckPerformActionAllowsRevisionsWhenNotConfigured( array $getValMap, string $msg ) { $output = $this->createMock( self::$outputPageClassName ); @@ -238,53 +237,6 @@ public function testCheckPerformActionAllowsHistoryRelatedWhenNotConfigured( $this->assertTrue( $service->checkPerformAction( $output, $user, $request ), $msg ); } - /** - * Data provider for history-related parameters that should be - * allowed when 'history' is not in CrawlerProtectedActions. - * - * @return array - */ - public function provideHistoryRelatedRequestParams(): array { - return [ - 'action=history' => [ - [ - [ 'type', null, null ], - [ 'action', null, 'history' ], - [ 'diff', null, null ], - [ 'oldid', null, null ], - ], - 'action=history should be allowed when history not protected', - ], - 'type=revision' => [ - [ - [ 'type', null, 'revision' ], - [ 'action', null, null ], - [ 'diff', null, null ], - [ 'oldid', null, null ], - ], - 'type=revision should be allowed when history not protected', - ], - 'diff=42' => [ - [ - [ 'type', null, null ], - [ 'action', null, null ], - [ 'diff', null, '42' ], - [ 'oldid', null, null ], - ], - 'diff=42 should be allowed when history not protected', - ], - 'oldid=99' => [ - [ - [ 'type', null, null ], - [ 'action', null, null ], - [ 'diff', null, null ], - [ 'oldid', null, '99' ], - ], - 'oldid=99 should be allowed when history not protected', - ], - ]; - } - /** * @covers ::checkPerformAction */