Problem/Motivation
follow-up #3323461: Hosting environment (e.g. cPanel) may add additional files (including symlinks) to the project, which breaks AU — in response to questions raised at #3323461-7: Hosting environment (e.g. cPanel) may add additional files (including symlinks) to the project, which breaks AU
In that issue a site was having problems because the Composer project for Drupal was installed at the base of the hosting account. So in the directory where the project's composer.json was there were other folders such as .cpanel. Some of these folders had symlinks so our SymlinkValidator was stopping Package Manager from working. Even if these folders did not have symlinks there would still be a problem because package_manager by default works by assuming everything under project root should be staged unless a folder is explicitly excluded. If we staged a folder like .cpanel and a change was made to the system this folder after we staged it we could wipe out these changes when we applied the update.
The main reason package_manager stages the whole project directory is because unfortunately even though something is not in the install path of a Composer package does not mean it is not managed by Composer. For instance our drupal/core-composer-scaffold plugin puts index.php and other files in their places and when a core update happens these files might be updated. But if we looked for the path index.php and the other files it manages under any of the install_path's of the packages that Composer knows about they would not be present. Of course we ship with drupal/core-composer-scaffold so we could special case these files.
The problem is if we special case these files then we are implicitly declaring that no other composer plugin can act like drupal/core-composer-scaffold and manage files outside it's install_path because we would not know about the files it manages.
So by default package_manager has been including everything inside the Composer project expect things that explicitly excluded. We exclude paths we know should excluded like the Sqlite db file or the files folder, see the classes under package_manager/src/PathExcluder. Basically we did this because we determined because of how Composer plugins work there is no 100% sure way of knowing what is managed by composer. If we accidentally exclude files that are managed by composer these files will not get updated if a new version of package updates these. Since we don't know the purpose of the files we might miss it is probably best to assume they are critical
Proposed resolution
Create a package manager enforce that only know Composer plugins are allowed.
This validator should:
- ✅
Subscribe to pre-create, pre-apply, and status-check events - ✅
Check the active and staged(if exists) directories - ✅
Add an error if there are any packages that requirecomposer-plugin-apiand are allowed via settings of the current composer project(there may be an API that determines this?) and are not in the list of allow plugins - ✅
Allow specifying additional allowedcomposerplugins through configuration (with initially just a$config['package_manager.settings']…line), a UI is for later: #3334906: Improve UX for trusting additional composer plugins
Remaining tasks
- ✅
Create a core policy issue to be clear that projects with other Composer plugins will have to set this setting→ #3335918: [Policy, no patch] Projects depending on composer plugins will have to update the additional_trusted_composer_plugins setting in package_manager.settings - Deviated from point 3, see question in #9:
why do we need to check if a package requires
composer-plugin-api? Why can't we just checktype === 'composer-plugin'?
User interface changes
Instead of allowing all composer plugins by default, restricting to only explicitly trusted composer plugins.
API changes
package_manager.settings configuration now has a additional_trusted_composer_plugins setting, which accepts a list of package names.
The following composer plugins are supported by default:
drupal/core-vendor-hardeningdrupal/core-composer-scaffolddrupal/core-project-messagedealerdirect/phpcodesniffer-composer-installerphpstan/extension-installercweagans/composer-patches
(The first 3 are Drupal core's (of which the first comes with an associated excluder: VendorHardeningExcluder), the 4th and 5th are used for Drupal core development and don't interfere with php-tuf/composer-stager and the last one comes with explicit validation: ComposerPatchesValidator.)
Data model changes
None.
Issue fork automatic_updates-3331168
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
tedbowComment #3
wim leersOn it!
Comment #4
xjmComment #5
wim leersComment #6
effulgentsia commentedComment #7
wim leersFYI this will become more relevant in the Drupal world once the Recipes Initiative is further along:
— https://git.drupalcode.org/project/distributions_recipes/-/blob/1.0.x/do...
Comment #9
wim leersFirst, let's start with implementing the first three points of the proposed solution:
For the third point, I'm not quite sure why we need to check if a package requires
composer-plugin-api? Why can't we just checktype === 'composer-plugin'? That's what I went with for now.⚠️ Failures expected
I expect the commit I just pushed (
ed7ef929396880a97c921e5f7bb16c3f3c477e21) to fail because of:PreOperationStageEvent::addError()\Drupal\fixture_manipulator\FixtureManipulator::setPackage()for dealing with pretty vs non-pretty package namesComposerPatchesValidator— already captured at #3252299-17: Reliably support cweagans/composer-patches in Package Manager & Automatic Updates: validate stage 👉 postponing this issue on that one ⚠️ComposerPatchesValidatoris nonsensical (it complains about a non-existentconfig.jsonfile) due to #3328234: Improve test DX *and* confidence: stop using VFS 👉 postponing this issue on that one ⚠️ (and actually HEAD is already wrongly testing that since #3314137: Make Automatic Updates Drupal 10-compatible, but only because of #3328234: Improve test DX *and* confidence: stop using VFS…)The first two are trivial fixes but nonsensical to write separate tests for, so I propose to fix those here. The other two I'll provide fixes for here so we can continue development here, but this MR should not land with those fixes.
Next
After fixing those failures, I'll address point 4 of the proposed solution.
Question
The issue summary seems to imply that a better solution still would be to flip the architecture around entirely, and switch from exclusions to inclusions. If we are to only support specific composer plugins, and each of those would require explicit vetting, then that would be possible. That'd of course be a drastic change, with big consequences.
But in security, in general, exclusions are considered a bad practice. So why was the architectural decision made to include everything, but allow exclusions, instead of the other way around? 🤔 This is not documented in
package_manager.api.phpand should be. Will update #3318306: Define the Package Manager API (package_manager.api.php is outdated).Comment #10
wim leersJust pushed
6e35d17— that fixes the second bug mentioned in #9, and will make these failures disappear:Comment #11
wim leersJust pushed
3c5e5a7, that fixes the first bug mentioned in #9, and will make these failures disappear:Comment #12
wim leersJust pushed
1d22833, that fixes the third bug mentioned in #9, and will make these failures disappear:plugin is installed, but the
composer-exit-on-patch-failurekey is not set totruein theextrasection of composer.json.'- )
- 'summary' => null
- )
)
Comment #13
wim leers8 of the 9 failures are
Buildtests. The 9th failure should be fixed in4bb2458which I just pushed.Comment #14
wim leersUp until #13, we were getting:
👆 These failures do not indicate at all what is happening! 😬
So I just spent a shockingly long time improving the DX for this, for the next poor soul who is working on adding a validator… 😊 Let's find out in the morning 😴
Comment #15
wim leersGreat, now we got this instead:
🥳
Comment #16
wim leersThe test coverage improvements between #13 and #15 also unblock other issues — see #3319679-19: Assert known preconditions for test runs and fail early if unmet. Tagging .
Comment #17
wim leersA single failure on
9.4.7:→ because we're now explicitly asserting that no error messages appear prior to installing a package, but that error message was present all along. Because that test still is being told that Drupal 9.8.1 is the latest version available, and we're on 9.4.x, so "a new sec release" is available — unlike on
10.1.x, for which9.8.1evidently is not a viable security update! So the test is in part testing the wrong thing; it should have been testing only that module updates were available, not core updates.Fix pushed:
6e97f1a88a706b32cd797c71ae634691424c1946.Comment #18
wim leersOverhauled issue summary to reflect current status and to reflect direction for the remaining work after having discussed with @tedbow 😊
Comment #19
wim leersThat test coverage works, but:
PreCreateEvent, we should also do it forPreApplyEventjust to be safe.Fixed in
116892a05c1e3f605206e16acb70d935ba39238c, which should get us to:Comment #20
wim leersWhat's still needed is updating
package_manager.api.php. Tagging for that.This can already be reviewed today, even though there's 2 blockers still preventing this from landing.
Comment #21
wim leers#3328234: Improve test DX *and* confidence: stop using VFS is in!
Comment #22
wim leersMerged in
8.x-2.x, which includes #3328234: Improve test DX *and* confidence: stop using VFS. The changes that were made there made it all the more awkward to make the changes here that #3252299: Reliably support cweagans/composer-patches in Package Manager & Automatic Updates: validate stage should make. So … removed them, and instead commented out the ~20 LoC that will ensure full test coverage of this issue's new validator combined withComposerPatchesValidator.And that made me realize that in fact this issue should move forward already without #3252299: Reliably support cweagans/composer-patches in Package Manager & Automatic Updates: validate stage having landed, because this makes it more clear in what way HEAD's
ComposerPatchesValidatoris not yet dealing with all edge cases. So: pushed3bdc3eato uncouple it and now unpostponing!Comment #23
wim leersDocumentation added.
Comment #24
wim leersCore policy follow-up created: #3335918: [Policy, no patch] Projects depending on composer plugins will have to update the additional_trusted_composer_plugins setting in package_manager.settings.
Comment #25
wim leersThis is ready for final review from @tedbow.
Comment #26
tedbowNeeds work for MR question
Comment #27
wim leersResponded on MR. Thank you. This made me realize we need a new issue, which actually is technically unrelated to this issue, but it was definitely discovered thanks to this issue — tagging to ensure we don't forget 😊
Comment #28
wim leersLet's wait a moment here, because I think a lot of the stuff this had to do could land in #3320792: Make build tests fail 1) more explicitly, 2) earlier when possible (failing StatusCheckEvent subscribers)…
Comment #29
wim leersCreated one more
core-post-mvpfollow-up: #3336867: Identify & vet commonly used composer plugins in the Drupal ecosystem.Comment #30
wim leersDiscussed with @tedbow in detail. #3320792: Make build tests fail 1) more explicitly, 2) earlier when possible (failing StatusCheckEvent subscribers) will incorporate the changes to
Buildtests that this issue made. That means this issue is now officially postponed on that one.All follow-ups were created.
Once #3320792: Make build tests fail 1) more explicitly, 2) earlier when possible (failing StatusCheckEvent subscribers) lands, the changes in this MR will be significantly smaller and easier to review, so let's wait for that 😊 Assigning to me to update it after that lands. 👍
Comment #31
tedbow#3320792: Make build tests fail 1) more explicitly, 2) earlier when possible (failing StatusCheckEvent subscribers) fixed
Comment #32
wim leersRebased on top of #3320792: Make build tests fail 1) more explicitly, 2) earlier when possible (failing StatusCheckEvent subscribers).
Comment #33
wim leersAnd now removed the remaining out-of-scope-but-discovered-here changes from this MR and adding them to #3337049: Assert no errors after creating the test project in ModuleUpdateTest 👍
Comment #34
tedbowcreate follow-up #3338346: Do not allow drupal/core-composer-scaffold to be used by packages other than core
Comment #35
tedbowNeeds work for MR comments
Comment #36
wim leersDiscusssed with @tedbow, I'm 70% of the way through implementing this — I thought it'd be trivial but because now we need to modify
composer.json, I also need to modify theFixtureManipulator… 😬Probably will be unable to finish this tonight; almost need to run for dinner. Definitely to be continued tomorrow!
Comment #37
wim leersGot it working, but still need to expand the test coverage for the new possible failure modes tomorrow.
Comment #38
wim leersAddressed all of @tedbow's feedback, test coverage expanded accordingly, and found a critical bug in my test coverage while doing so 👍
Also thoroughly documented the rationale behind the architecture in the class-level docblock, so that the results of the conversatino @tedbow and I had are available for posterity 😊
Comment #39
tedbowNeeds work at least to use the Composer Inspector
Comment #40
tedbowRTBC
@Wim Leers if I didn't address your question well enough in https://git.drupalcode.org/project/automatic_updates/-/merge_requests/65...
lets make a follow-up
Comment #42
tedbowThanks @Wim Leers!
Comment #43
wim leers@tedbow I’m really glad that this landed, but I worry that introducing version restrictions on the supported composer plugins later will constitute a BC break — not just for the configuration, but also for the behavior of the "out of the box supported" composer plugins.
Is that not a concern for you?
Either way, it's good to have this landed, we can add version constraints in a next issue. And I agree with your remark that you posted just prior to committing:
\Drupal\package_manager\Validator\ComposerPatchesValidatorshould be markedfinaland@internal. Perhaps we can do all of that combined in acore-mvpfollow-up?Comment #44
wim leersDiscussed #43: #3340022: Tighten ComposerPluginsValidator: support only specified version constraint.