Add configurable action protection via $wgCrawlerProtectedActions#14
Add configurable action protection via $wgCrawlerProtectedActions#14
Conversation
Co-authored-by: jeffw16 <11380894+jeffw16@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds a new extension configuration option to make which action= requests are blocked for anonymous users configurable (previously hardcoded to action=history).
Changes:
- Introduces
CrawlerProtectedActionsconfig (default["history"]) to preserve existing behavior. - Updates the
MediaWikiPerformActionhook to consult config and block configured actions for anonymous users. - Documents the new option and adds/updates unit tests and test stubs.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
extension.json |
Adds CrawlerProtectedActions config with default ["history"]. |
includes/Hooks.php |
Reads CrawlerProtectedActions from MainConfig and uses it to decide whether to deny anonymous requests. |
README.md |
Documents $wgCrawlerProtectedActions usage. |
tests/phpunit/unit/HooksTest.php |
Adds tests for action=history behavior. |
tests/phpunit/namespaced-stubs.php |
Extends the stub config to return a default CrawlerProtectedActions value. |
|
|
||
| $request = $this->createMock( self::$webRequestClassName ); | ||
| $request->method( 'getVal' )->willReturnMap( [ | ||
| [ 'action', null, 'history' ], |
There was a problem hiding this comment.
Same issue as above: the getVal() mock map includes a null default parameter, but the code under test calls getVal( 'action' ) with one argument. As written, this will likely return null and not test the intended behavior.
| [ 'action', null, 'history' ], | |
| [ 'action', 'history' ], |
| // 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.
These history-action tests are skipped whenever the real MediaWikiServices is present, but Hooks::onMediaWikiPerformAction() now always uses MediaWikiServices::getInstance()->getMainConfig(), and the other onMediaWikiPerformAction tests in this file are not skipped. This skip will unnecessarily drop coverage in a real MediaWiki test run; consider removing it (or only skipping when CrawlerProtectedActions cannot be read).
| // 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.' | |
| ); | |
| } |
| if ( $name === 'CrawlerProtectedActions' ) { | ||
| return [ 'history' ]; | ||
| } |
There was a problem hiding this comment.
namespaced-stubs.php hardcodes CrawlerProtectedActions to [ 'history' ], which makes it impossible to unit-test the new configurability (e.g., verifying that an empty array allows action=history, or that another action can be protected). Consider making this stub value controllable (e.g., via a static property) so tests can cover non-default configurations.
|
|
||
| * `$wgCrawlerProtectedActions` - array of actions to protect (default: `[ 'history' ]`). | ||
| Actions specified in this array will be denied for anonymous users. | ||
| Set to an empty array `[]` to allow all actions for anonymous users. |
There was a problem hiding this comment.
The README says setting $wgCrawlerProtectedActions = [] will "allow all actions for anonymous users", but anonymous users will still be blocked by the other checks in onMediaWikiPerformAction (type=revision, diff, oldid). Consider rewording to clarify that this only disables the action=-based restriction.
| Set to an empty array `[]` to allow all actions for anonymous users. | |
| Set to an empty array `[]` to disable `action=`-based restrictions for anonymous users (other checks | |
| such as `type=revision`, `diff`, or `oldid` may still block requests). |
| $config = MediaWikiServices::getInstance()->getMainConfig(); | ||
| $protectedActions = $config->get( 'CrawlerProtectedActions' ); | ||
|
|
||
| if ( | ||
| !$user->isRegistered() | ||
| && ( | ||
| $type === 'revision' | ||
| || $action === 'history' | ||
| || in_array( $action, $protectedActions, true ) |
There was a problem hiding this comment.
CrawlerProtectedActions is now configurable, but there are no tests covering non-default configuration values (e.g. empty array allowing action=history, or protecting an additional action). Adding such cases would ensure the new config wiring is actually exercised and remains stable across MediaWiki versions.
|
|
||
| $request = $this->createMock( self::$webRequestClassName ); | ||
| $request->method( 'getVal' )->willReturnMap( [ | ||
| [ 'action', null, 'history' ], |
There was a problem hiding this comment.
The getVal() mocks use willReturnMap entries with two parameters ([ 'action', null, 'history' ]), but Hooks::onMediaWikiPerformAction() calls $request->getVal( 'action' ) with a single argument. That means the map entry won’t match and the mock will return null, so this test won’t actually exercise the history-action branch. Update the mock to match the one-arg call (or provide map entries for both 1-arg and 2-arg invocations).
| [ 'action', null, 'history' ], | |
| [ 'action', 'history' ], |
The extension hardcoded
action=historyblocking for anonymous users. This adds$wgCrawlerProtectedActionsconfiguration to make it customizable.Changes
extension.json): Added$wgCrawlerProtectedActionswith default["history"]to maintain backward compatibilityincludes/Hooks.php): Replaced$action === 'history'within_array( $action, $protectedActions, true )using config fromMediaWikiServicesREADME.md): Documented the new configuration option with usage examplesUsage
Default value
["history"]preserves existing behavior.Warning
Firewall rules blocked me from connecting to one or more addresses (expand for details)
I tried to connect to the following addresses, but was blocked by firewall rules:
https://api.github.com/repos/PHPCSStandards/PHPCSExtra/zipball/746c3190ba8eb2f212087c947ba75f4f5b9a58d5/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/fbMmTh /usr/bin/composer install(http block)/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/PHPCSStandards/PHPCSUtils/zipball/908247bc65010c7b7541a9551e002db12e9dae70/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/fbMmTh /usr/bin/composer install(http block)/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/14f5fff1e64118595db5408e946f3a22c75807f7/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/fbMmTh /usr/bin/composer install(http block)/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/845eb62303d2ca9b289ef216356568ccc075ffd1/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/fbMmTh /usr/bin/composer install(http block)/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/composer/semver/zipball/35e8d0af4486141bc745f23a29cc2091eb624a32/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/fbMmTh /usr/bin/composer install(http block)/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/composer/spdx-licenses/zipball/edf364cefe8c43501e21e88110aac10b284c3c9f/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/fbMmTh /usr/bin/composer install(http block)/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/nikic/PHP-Parser/zipball/dca41cd15c2ac9d055ad70dbfd011130757d1f82/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/php-parallel-lint/PHP-Console-Color/zipball/7adfefd530aa2d7570ba87100a99e2483a543b88/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/php-parallel-lint/PHP-Console-Highlighter/zipball/5b4803384d3303cf8e84141039ef56c8a123138d/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/php-parallel-lint/PHP-Parallel-Lint/zipball/6db563514f27e19595a19f45a4bf757b6401194e/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/2b56bea83a09de3ac06bb18b92f068e60cc6f50b/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/sebastianbergmann/comparator/zipball/e4df00b9b3571187db2831ae9aada2c6efbd715d/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/sebastianbergmann/complexity/zipball/25f207c40d62b8b7aa32f5ab026c53561964053a/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/sebastianbergmann/diff/zipball/ba01945089c3a293b01ba9badc29ad55b106b0bc/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/sebastianbergmann/exporter/zipball/14c6ba52f95a36c3d27c835d65efc7123c446e8c/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/sebastianbergmann/global-state/zipball/b6781316bdcd28260904e7cc18ec983d0d2ef4f6/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/e1e4a170560925c26d424b6a03aed157e7dcc5c5/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/85402a822d1ecf1db1096959413d35e1c37cf1a5/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b36f02317466907a230d3aa1d34467041271ef4a/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/539c6691e0623af6dc6f9c20384c120f963465a0/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/05d5692a7993ecccd56a03e40cd7e5b09b1d404e/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/symfony/console/zipball/41e38717ac1dd7a46b6bda7d6a82af2d98a78894/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/380872130d3a5dd3ace2f4010d95125fde5d5c70/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/fbMmTh /usr/bin/composer install(http block)/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/fbMmTh /usr/bin/composer install(http block)/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/symfony/service-contracts/zipball/45112560a3ba2d715666a509a0bc9521d10b6c43/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/symfony/string/zipball/1c4b10461bf2ec27537b5f36105337262f5f5d6f/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/theseer/tokenizer/zipball/b7489ce515e168639d17feec34b8847c326b0b3c/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/wikimedia/mediawiki-tools-codesniffer/zipball/c559bc02e87b0a969b6ed7380d7fa1d02738158b/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/wikimedia/mediawiki-tools-minus-x/zipball/553f920ad53f78b33ea654f8623c2a50b5ac7efd/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/iyUitq /usr/bin/composer install --no-interaction(http block)If you need me to access, download, or install something from one of these locations, you can either:
Original prompt
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.