[2.x] fix: return an empty collection when there is no installed.json to read - #4946
Open
karl-bullock wants to merge 1 commit into
Open
[2.x] fix: return an empty collection when there is no installed.json to read#4946karl-bullock wants to merge 1 commit into
karl-bullock wants to merge 1 commit into
Conversation
ExtensionManager::getExtensions() is declared to return a Collection, but only assigns one when vendor/composer/installed.json exists. When it does not, the property stays null and the method returns null, so PHP raises TypeError: getExtensions(): Return value must be of type Illuminate\Support\Collection, null returned on every call. The missing-file case is not hypothetical: it is exactly the state a forum is in partway through a composer operation, which is also when the admin panel is most needed to recover. A fatal there turns a recoverable moment into a white screen. Returns an empty collection instead, which is what getInstalledPackageNames() directly below already does for the same file. It is deliberately not cached, so the next call picks the extensions up once composer has written the manifest. Found by running the extension manager's integration suite, where it accounted for all 28 errors.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Affected versions: reproduced on
2.0.0-rc.5. The code is unchanged on2.xatff36902(Application::VERSION=2.0.0-rc.6), so it still applies. This PR is based on that commit.ExtensionManager::getExtensions()is declared to return aCollection, but only assigns one whenvendor/composer/installed.jsonexists. When it does not, the property staysnulland the method returnsnull, so PHP raises:The missing-file case is not hypothetical. It is the state a forum is in partway through a composer operation, which is also the moment the admin panel is most needed to recover. A fatal there turns a recoverable situation into a white screen, and the people most likely to hit it are the ones without shell access to put it right.
This returns an empty collection instead, which is what the neighbouring
getInstalledPackageNames()already does for the same missing file. It is deliberately not cached, so the next call picks the extensions up once composer has written the manifest.Reproducing
On a stock
2.0.0-rc.5forum:Every request then returns 500 with the TypeError above. With this change the forum serves 200, the API answers, and restoring the file brings all extensions back with no restart.
I ran that in both directions on a throwaway forum: stock core with the manifest hidden gave 500 on every request; the same forum with only this change applied, manifest still hidden, gave 200; restoring the manifest listed all 17 extensions again.
One question for reviewers
This is a judgement call rather than a correctness one, so I would rather raise it than leave it implicit: you could argue a missing
installed.jsonshould fail loudly, and that quietly reporting zero extensions hides a broken install.My reasoning for the empty collection is that the forum boots and stays reachable, which is what lets somebody fix the install, and that the neighbouring method already treats the same missing file that way. If you would prefer an explicit exception with a clear message, I am happy to change it.
Testing
framework/core's own suites pass with the change in place (409 and 861 tests, no failures). PHPStan is clean.One correction to my commit message, which I cannot amend now that the branch is published: it says this was found by running the extension manager's integration suite. That is where I hit it, but that suite does not currently run on a clean checkout.
extensions/package-manageris absent frommonorepo_tests, itstests/integration/setup.phpstill requires../../vendor/autoload.phprather than the monorepo bootstrap, andcomposer test:setupfails because the fixture inSetupComposer.phppinsflarum/coreto1.0.0, which current Composer declines to install over published security advisories. So please do not take that line as a reproduction recipe. Themv installed.jsonsteps above are the reliable one.