While looking at the list of tests for an extension I found 3000+
ScopeStructureTest which are generated from the php files in
mediawiki/core (more precisely `$wgAutoloadLocalClasses`):
* those tests take 21 seconds to complete on my machine.
* None were generated for the extension being tested, those tests are
thus solely affected by mediawiki/core.
`tests/phpunit/structure` is included in the `extensions` and `skins`
PHPUnit testsuites and any patches made to them would run that 21
seconds suite even though its only testing mediawiki/core.
Move the test outside of `structure` so it is no longer run for
`extensions` and `skins`.
Bug: T225730
Change-Id: I628210b8b270773f3dad12bbde9d72f0328fcceb
(cherry picked from commit d10835b8bc933a49724010f0c39dfeaccfa9108c)
* Fix test failures
* Cherry-pick message cache change I957b6fb2bc0d9d4b1aae6e
* Cherry-pick part of I638d6d6d23f9624ba1dff0f4fcc to change cache from
static to non-static.
Change-Id: I77a2facf9923d38269538e48c79365fa117af9af
Follows-Up: Id5462b942f5e916c2f1dc725739615d54a1070de
Follows-Up: I5471fe615d222b936c6668bf3089dd8b5931cc75
Follows-Up: I7bbd6ae36a11840ed6b4620b5d07fa5158ff139e
CVE-2025-6927
In BlockListPager, restore the bl_deleted=0 condition removed in the
previous commit. Add tests.
Bug: T397595
Change-Id: I5471fe615d222b936c6668bf3089dd8b5931cc75
CVE-2025-6927
ApiQueryBlock was relying only on the filter returned by
HideUserUtils::getExpression which only works for blocks targeting a
user account
Bug: T397595
Change-Id: I7bbd6ae36a11840ed6b4620b5d07fa5158ff139e
A special page has access to the request context which includes the site
config, no need to inject that separately here.
Change-Id: If8f01466c64dbacf806b6fccfa0bc4736c259607
(cherry picked from commit 0110bba7c9a8bdaf1cd8579534300c76b29c038a)
Why:
- action=compare was used to circumvent Lockdown
What:
- use checkTitleUserPermissions() to enforce read permissions in
ApiComparePages.
Bug: T397521
Change-Id: Id275382743957004fa7fc56318fc104d8e2d267b
(cherry picked from commit c62e4d93a33e94c7fe6f716a4747b1dbd59b3f90)
Make SqlPlatform::tableNameWithAlias() include the unqualified table
name as an alias if doing so is not redundant. This assures that the
default alias from JoinGroupBase::addJoin(), equal to the unqualified
table name, will be usable in SQL (regardless of table prefixes).
Clean up use of identifier quotes for sqlite_master tables. The called
methods expect unqualified names and a passthrough exception already
exists for sqlite_* tables.
Use "block_target.bt_user" directly in ApiQueryBlocks and BlockPager,
instead of using addIdentifierQuotes(). The "block_target" alias is
automatically added to the SQL by the rdbms layer when it's not clearly
redundant, so it is always safe to use block_target.bt_user. Also, there
is no reason for aliases to include quote characters. They are supposed
to be simple alphanumerics like column names. This makes it easy for
tableNameWithAlias() to avoid redundant aliases by checking tableName().
Avoid unneeded quotes around pg_catalog.* table names in the Postgres
installer. The relevant documentation of methods like selectField() is
that the table names be unqualified (no quotes nor dots), though dots
are still supported internally for compatibility reasons and ease of
querying schemas like pg_catalog and information_schema.
Change-Id: Ic7d7826da31f49915141692cb3bd84ed1e872e96
This patch was applied to release branches for MW 1.42 in April 2024, and
since ported to MW 1.43 and then MW 1.44 as well. This one-of-a-kind hot
patch will finally discontinue once this lands in the master branch as
part of MW 1.45+ releases.
A small handful of phan fixes make this pass so it can land; the rest
(including fixes rather than suppressions of events here) will happen in
later patches.
Bug: T328921
Bug: T359868
Change-Id: Ica2c11a6243795437ec652923e42ef3bd74a5fd8
psr/log 3.0.0 adds this return type.
For this specific case the fix is very simple, fully
compatible with the older version of psr/log, and
something we’ll have to do sooner or later anyway.
Bug: T356451
Change-Id: I49562ac7f1a71e82cab79fe44296feea573e26d4
(cherry picked from commit 9244d4b2623b9d789e7dea28e65b5ca6f9651aaf)
It was added in 2016 as part of SessionManager (Ic1ffea74f3, later
re-attributed to Ibb3e023e4e) by Anomie. It wasn't used at the time.
Basically, it is used for cases where we expect no logs, and the
presence of logs will then produce a failing test. The point is to do
something that PHPUnit will "complain" about by showing it. Emitting
a notice or warning is one way, another is to simply echo it, since
output is also unexpected and shown. The somewhat arbitrary mapping
from log levels to PHP error codes isn't used.
Later in 2017, he introduced the same class in php-session-serializer
(I2ebf59414ef9a9) where this part was already removed and replaced
by "echo". The version in core still used trigger_error.
== Why now ==
Triggering E_USER_ERROR is deprecated in PHP 8.4+.
Bug: T379445
Change-Id: Id1e1db80bc8fea39cd192716597e5e4a6f4966b0
(cherry picked from commit 5a1a8c14bd418c846498cd4ed99b77e45a0fcca1)
For a long time now, since PHP 7.0.0, access to non-public properties
has thrown Error, not emitted E_ERROR.
Example - https://3v4l.org/dHChU
Our simulation of this in DeprecationHelper is meant to do what PHP
does, so, given we no longer support PHP 5.6 and can thus construct
Error ourselves, we should do the same.
This is identical - https://3v4l.org/koUqu
== Why ==
Referencing the E_USER_ERROR constant causes a deprecation warning
in PHP 8.4+.
== Change ==
The source change is straight-forward.
One of the tests (testSet, dataset 4 "fallbackGetterOnly") was
previously passing by accident. The source called trigger_error twice,
first with E_USER_DEPRECATED (via wfDeprecated) and then again with
E_USER_ERROR. Given that these are asserted via set_error_handler,
an event calback, the callback is run after the callback finished
(it does not interrupt), at which point only the last values are
reported to the event handler. Improve on this by explicitly hiding
the deprecation warning, and focus the case on testing the error.
Bug: T379445
Change-Id: Ia0aff9906102023370f3907e01962a5e1e369125
(cherry picked from commit d0920b8fb5be462a7aba5c21e47b02c2c2f5025f)
php8.4 prints more information into the string "{closure}".
The text is now "{closure:DeprecationHelperTest::testSet():124}"
Change-Id: I4c54a089ad981ba03da21f50cbeebb48ea8e1d28
(cherry picked from commit eea57fa92c043a1e0571b24d7a88a8d7f0ed3bf7)
Why:
- Using an anonymous user object at the start of account creation helps
ensure that downstream code paths do not record the association
between a temporary account and a named account
What:
- Use an anonymous user object during account creation initiated by
temp account users
- Update the session to use the anonymous user and set the request
context user based on the session user
- Ensure the temp account username is removed from the session, to avoid
issues where account creation fails and code thinks that a temporary
account username is already defined for the session
- Add a test to exercise this code path
Bug: T393628
Change-Id: I6d2df8c1d842c4fefa916ed395479f479a0051eb
(cherry picked from commit 3d80e63f109834b90a83597d6d924895b2c6ae71)
Why:
- Various tests have been calling Title::clearCaches() on an ad-hoc
basis at the end of test methods, or in tearDown(), to work around
stale Title instances persisting across tests in Title's internal
caches.
- MediaWikiIntegrationTestCase takes care of this since
Ie6cac7e1282f794277dfc8ff3673f12e9969818c, making these calls
unnecessary.
What:
- Remove now-redundant Title::clearCaches() calls from tearDown()
overrides and the end of test methods.
- Preserve in-test Title::clearCaches() calls that are likely
intended to force internal caches to reflect changes happening
within the test itself.
Bug: T395214
Change-Id: Ib5d42389cef20f3839c7f7a80041d002f0f09449
(cherry picked from commit 6483181044496c339ad497cc885319b20de7f6e7)
Why:
- Title has several in-memory caches for Titles constructed via
newFromText() and for the canonical mainpage instance that
isMainPage() compares against.
- These caches are not reset between tests, which can cause cryptic
integration test failures. It's not safe to persist either of these
caches across tests, as neither the internal state of Title objects nor
the identity of the canonical mainpage is valid across tests.
What:
- Clear the cached main page instance in Title::clearCaches().
- Call Title::clearCaches() from MediaWikiIntegrationTestCase::resetNonServiceCaches().
Bug: T395214
Depends-On: Ic35b45015ff5a53f6e728b69b59cc57efe0b390b
Change-Id: Ie6cac7e1282f794277dfc8ff3673f12e9969818c
(cherry picked from commit 3f7905bc9ff9006831f8573b7fe948dc7243107e)
Without brace expansion the result is empty.
The test counts as skipped test
Follow-Up: I757eb043f8043d6620fb69bd072d9bb9e97ad163
Change-Id: I394c58887a30befe25ed72897bf0608b49f37b0d
(cherry picked from commit 030a951e142d15e90fbee16d2bf1571505e4c2a6)
Catch the exception and return Http Code 400 as already done in the
class for the non-redirect code path.
To get the exception, visit /thumb.php?f=Redirect.jpg
Bug: T387684
Change-Id: I45202572dfce8b60a8aed9343f7d99e2eee12415
(cherry picked from commit b43c89b297e895cb77fbf0f9efd987c6dbf7f50e)
When q is not followed by =, the array has not enough items and
unpacking results in undefined array key. Also $val is set to null,
resulting in php deprecation warning on trim()
Bug: T391867
Change-Id: Ia5d4c9b6fb788ad4390d2562c6f38682f280a634
(cherry picked from commit cda46ed9f0c31280a8db59a2f0387e64e6308906)
CVE-2025-32699
Ensure that Unicode NFC normalization can be applied to our HTML
output safely. Even though the W3C officially recommends against
normalizing HTML
https://www.w3.org/International/questions/qa-html-css-normalization#converting
this is still easily done inadvertently, especially when using the
MediaWiki action API which normalizes parameters and results by
default.
See also I671648603c4635a35585c860b4857f5ea085e47f in Parsoid, and
T266140 / I2e78e660ba1867744e34eda7d00ea527ec016b71 for another similar
issue.
The following changes are made:
* The various HTML serializers (Remex/Tidy-derived, as well as the
Html::* helpers) are tweaked to entity-escape U+0338 wherever it
appears.
* Similarly, Message::escaped() is tweaked to entity-escape U+0338.
* Finally, a post-processing pass is added to the OutputTransform
pipeline to catch any remaining U+0338 and entity-escape them.
This catches U+0338 added during any of the previous OutputTransform
stages (like TOC insertion, section edit links, etc).
*When backporting* this code will likely need to be moved to
ParserOutput::getText(), as the OutputTransform pipeline wasn't added
until MW 1.42.
Bug: T387130
Change-Id: I66564e14e730f5393f4fa5780b80f24de6075af5
Same as was done in 5f2584b648
Bug: T391586
Follows-Up: I966cddb337c9373ed3a369496548a8d8c538ae84
Change-Id: I757eb043f8043d6620fb69bd072d9bb9e97ad163
(cherry picked from commit 7a84c34398639d3422f81ab9711539c34d435621)
A crude solution for the acquireTarget() race condition. Use SQL
GET_LOCK() to lock the target from the acquireTarget() call until the
transaction is committed.
Add FOR UPDATE to the acquireTarget() SELECT, otherwise it just sees the
snapshot version of the row and inserts a new row anyway.
Add a test which reliably failed prior to the change.
Reword the ipb-block-not-found message. This is normal for simultaneous
blocks of the same target. Don't contact us. In the API, remap it to
"alreadyblocked".
Bug: T389028
Change-Id: I1fa35bf08d456a93930194786f77df389217ba61
(cherry picked from commit 2b65587e4d92e7f27661e8821b14f74ade939cfa)
Added in 2022 with I7d97c9e2d4 (c6a0d433ec) for Ie430acd075
(e82f11c246) which was (after a revert and re-apply) eventually
removed after the warmup completed (I852060c8a4, 3df4952385).
Bug: T322672
Bug: T387478
Change-Id: I1921b4f985fb27b2227aef4a0eba6751c1c0b8d5
(cherry picked from commit 2a5cf3fde93263156557bc1efd21c5a74ce67725)
These .htaccess files are intended to prohibit all web access. But if
the user sets "Satisfy Any" on a parent directory, in conjunction with
any permissive require directive like "Require all granted", access will
be allowed despite "Require all denied" in .htaccess.
So, override Satisfy so that the "Require all denied" will reliably take
effect.
Note that "Satisfy All" is the default. This only affects non-default
installations.
Change-Id: Ia5862fb69e439b7ea2ed7af011e1ebf8f1b1f6d6
(cherry picked from commit a50d2e69f8ce9e5720b05615d04c35cc9008b6ae)
Why:
`ChangeTags::buildTagFilterSelector` is an opinionated chain of calls
that results in the markup for a select input with specific tag options
(explicitly and software defined tags that have hits). In order to
support customization to the `HTMLTagFilter` widget, add support for
parameters.
These parameters will support filtering for active-only tags or not
and choosing between all on-wiki tags or software-defined tags only.
What:
- Support an `activeOnly` parameter, which will either show all defined
tags or only tags that have hits (active)
+ For legibility, add `TAG_SET_ACTIVE_ONLY` and `TAG_SET_ALL` constants
to support this parameter
- Support a `useAllTags` parameter, which if true will use all tags
and if which false will only use software-defined tags
+ For legibility, add `USE_ALL_TAGS` and `USE_SOFTWARE_TAGS_ONLY`
constants to support this parameter
Bug: T378622
Change-Id: Ib6ba27944cdf22bdb05dbfd34b2e5f8727261da7
This patch reworks RestrictionStore::getCascadeProtectionSourcesInternal
to return a third and fourth array:
* One for cascading restrictions originating from templatelinks
* Another for those originating from imagelinks
They are used in PermissionManager::checkCascadingSourcesRestrictions
to differentiate cascading protection of file content and file page,
but could also be used in the future by action=info and other callers.
Bug: T24521
Bug: T62109
Bug: T140010
Change-Id: Ia5863f418538106f4fd657c672298ff6ac835805
(cherry picked from commit 7a4952ef2c5d593fae9419bad39f3e9894f42adf)
Why:
- PermissionManager::getUserPermissions() checks whether the user is
blocked if $wgBlockDisablesLogin = true, so that it can then limit
user's permissions to the set of permissions assigned to unregistered
users if so.
- This causes the GetUserBlock hook to run, which may itself check
permissions on the user (e.g. in the GlobalBlocking extension),
causing an infinite loop.
- Since the decision whether the user is blocked isn't yet final by the
time GetUserBlock runs, any permission checks triggered by
GetUserBlock handlers should see the user's full set of permissions.
What:
- Stash the user's permissions in PermissionManager's in-memory cache
before running block checks if BlockDisablesLogin = true.
- Add tests.
Bug: T384197
Change-Id: I3e3804fe518627e9edc2b574cce88f533fd93fe4
(cherry picked from commit 27062b9f8752cc853a65e8a46c9d7d1a9af32c48)
Why:
- Revision meta-data output was failingfor revisions with suppressed
user or comment
What:
- Handle suppressed user and comment gracefully
- add regression test
Bug: T386368
Bug: T387397
Change-Id: Ic6d3fc89d24030f5c3fd422637816de9976fc709
(cherry picked from commit 8c53a15ba0fae2677aa8e28055f06ef557595be6)
Why:
- Setting the increment to 0 should check the limit without bumping it.
- This was apparently broken by If3e66491306f22650.
What:
- Use LimitBatch::peek if the increment amount is 0
Bug: T381033
Change-Id: Ife76a1976a2063f051f00302e5adaebd701e6367
(cherry picked from commit e09606b3dc44711571cc6cf2d0d11bd7784d0cdd)
If $mailparts does not contain two elements (which would be the case when the separator `@` is not present in the string), then we cannot
access $mailparts[1].
In this case, the entire path as is, is treated as the host.
Bug: T380880
Change-Id: I10187c93e67ce9294ff0b3866939d2c7d7292a9a
(cherry picked from commit c2db58c55bef207dd37ac5fe0b07aa28ee4bd2d5)
Why:
- The REST API takes an optional renderid param when converting HTML
back to source wikitext, which is user-provided and may be invalid.
- Invalid render IDs cause an InvalidArgumentException to be thrown that
causes a 500 response.
What:
- Introduce a new error message for invalid render IDs in the REST API.
- Return a 400 with this new error message for HTML reverse-parses with
an invalid render ID.
Bug: T385568
Change-Id: I062419fe8952329a39781a49cdca2e94c3996447
(cherry picked from commit cd1d42a5066e4bcb9b9d4ed9b4f7714fd428fea3)
Why:
- ParsoidRenderID::newFromKey() validates incoming keys and throws an
InvalidArgumentException if a required key component was missing.
- It does so by eagerly destructuring the return value of explode(),
which causes a PHP Notice for invalid inputs as the expected offsets
won't exist then.
What:
- Check the count of key parts before destructuring.
- Add unit tests.
Bug: T385567
Change-Id: I1d936ae038f85ffa2e5d1d3d8a75fdc75e4c8ef8
(cherry picked from commit eec130925c081c2da1c475f9a9ce719e6838ca51)
SemanticMediaWiki creates its own bootstrap and displays
a bunch of information. In [0] this broke this.
We already look for bootstrap anyways, we just don't use it.
We fix this by checking for bootstrap and only setting a default
if not supplied.
[0] d2a30096f1
Change-Id: Iebb1949cc6a253640f40f1ac048ab50f99cac02a
(cherry picked from commit d43c69b25f05801ac3c255a2dfdbe03e820029ca)
session.use_trans_sid is a PHP antifeature that tells PHP to add
session IDs to all local URLs by modifying the HTML it's told to
output. We have set it to false just in case, but now that's
triggering deprecation warnings.
Bug: T380755
Change-Id: Iace0dcdb23eedb432cc1c032bbb3ce31d34071be
(cherry picked from commit 3b948a3da4be2a20573db01d611d601f2f90f2e5)
This has been failing integration tests since 20250101 because all 2024
become 2025.
Bug: T382848
Change-Id: I5aa71bb7644cfb42140d8eaba9f408e762b2937c
(cherry picked from commit ba68c4494298bcaba7c8d1e1acaecff002cb3aac)
json_decode now emits a deprecation warning when called with null.
Before it would just return null anyway in these cases so I just
introduced a way around that avoids calling the mehod in the frist
place.
Bug: T382590
Change-Id: I47b7aca331a405bb3d2865cc280ef3ced537f84b
(cherry picked from commit b2fad75337256aaabd6e892bdd4bea8f86b47d5c)
Why:
- The test ClockTest::testShouldReturnCurrentTime is flaky.
- Ie48d9400cf3bb99467a16b9ea0cce6172e2e2568 recently augmented
the ConvertibleTimestamp library to allow faking hrtime(), which will
be a better solution for this class and test than the current
assertion.
What:
- Skip the test until core is updated to the latest version of
ConvertibleTimestamp.
Bug: T379562
Change-Id: Iae502ed0344f45f89da575f1c5d1e0fb9c1e4dfa
(cherry picked from commit a930114b4240ec311a56eef7f814f378cc3d5f88)
There's no point in retrying a job when you get "Revision x is not current".
It just causes log spam. Makes people think there's a problem when there isn't as it
logs in the error channel.
Bug: T379656
Change-Id: Iaa5bd006bf3f26277e81ad5bea1387ef4b925f68
Why:
* Special:PasswordReset allows users to send an email containing
a temporary password to the email address attached to an account.
* Temporary accounts do not have passwords and cannot have an email
address set (as they cannot access Special:Preferences).
* Therefore, Special:PasswordReset does not provide holders of
temporary accounts a way to get access back into the temporary
account if they loose access.
* However, the form currently accepts temporary account usernames
and we should update the functionality to reject such usernames.
What:
* Update SpecialPasswordReset to reject temporary account usernames.
* Expand tests for SpecialPasswordReset to check this fix has worked.
Bug: T380085
Change-Id: I004453d4d16cd2a0448ac3922e4d13c24a158c8d
(cherry picked from commit e27be818690820c0df227cb06206da499eb94d38)