Problem/Motivation

In #3528139: Package Manager should use a copy of Composer that is local to the current project, if available, I propose that we allow Package Manager to use a copy of Composer that is local to the project. This would greatly reduce friction when using Automatic Updates or Project Browser, or really, anything that uses Package Manager. It would particularly benefit people who use Drupal on shared hosting, who cannot always control which version of Composer they have (some hosts use outdated versions that Package Manager doesn't support, and are unwilling to update it).

However, the idea of keeping Composer's binaries in vendor runs into the wall that is drupal/core-vendor-hardening, which deletes Composer's binaries entirely and that's that.

Proposed resolution

The plugin should be configurable to skip cleaning certain packages, if desired. See #18 for proposed syntax.

Remaining tasks

Get reviews and sign-offs.

Release note

The drupal/core-vendor-hardening plugin now allows projects to opt out of cleaning certain packages. The default behavior is unchanged, but a project may add this to its composer.json to prevent a given package (composer/composer, in this example) from being cleaned:

"extra": {
  "drupal-core-vendor-hardening": {
    "composer/composer": false
  }
}

Or, at the command line:

composer config extra.drupal-core-vendor-hardening --merge --json '{"composer/composer": false}'

Issue fork drupal-3534278

Command icon 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

phenaproxima created an issue. See original summary.

phenaproxima’s picture

Title: The vendor hardening plugin should support changing the permissions of certain paths » The vendor hardening plugin should not remove Composer's binaries, but just make them read-only
Issue tags: +Needs issue summary update

After pondering the vendor hardening plugin, I think what might make the most sense is...to special-case composer/composer. We should still remove its binaries, so that vendor/bin/composer doesn't exist...but vendor/composer/composer/bin/composer should keep existing, and have its execute bit removed.

In other words, Composer's linked binaries won't exist anymore, but its original binaries will, without their execute bits.

I think that's the right balance between making Package Manager easier to use and not having to do an extensive refactor of the entire vendor hardening plugin and its configuration. It's also safer to just special-case this one package, for this specific purpose, rather than giving people the tools to make any binary persist (especially since I've never heard of another use-case for doing that).

phenaproxima’s picture

Assigned: Unassigned » phenaproxima

Discussed the above with @catch and Slack and the feeling seems to be that I should go ahead and create that MR, then let the security team and release managers consider it.

phenaproxima’s picture

Assigned: phenaproxima » Unassigned
Issue summary: View changes
Status: Active » Needs review
Issue tags: -Needs issue summary update +Needs security review, +Needs release manager review, +Drupal CMS release target

Tagging for security review to confirm that this solution doesn't introduce any security flaws, and release manager review to confirm that this change is non-disruptive and, hopefully, eligible for backport to 11.2.3.

Also tagging to point out that Drupal CMS needs this.

needs-review-queue-bot’s picture

Status: Needs review » Needs work
StatusFileSize
new2.7 KB

The Needs Review Queue Bot tested this issue. It fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".

This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.

Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

phenaproxima’s picture

Status: Needs work » Needs review

Get lost, bot.

needs-review-queue-bot’s picture

Status: Needs review » Needs work
StatusFileSize
new3.04 KB

The Needs Review Queue Bot tested this issue. It fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".

This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.

Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

phenaproxima’s picture

Status: Needs work » Needs review

The bot is wrong and stupid.

needs-review-queue-bot’s picture

Status: Needs review » Needs work
StatusFileSize
new3.04 KB

The Needs Review Queue Bot tested this issue. It fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".

This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.

Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

phenaproxima’s picture

Status: Needs work » Needs review
Issue tags: +no-needs-review-bot

What a nuisance!

longwave’s picture

Is there a case for making this configurable, at least with an on/off flag, for sites that will never use automatic updates and want to retain the existing behaviour?

longwave’s picture

Also the bot doing this has a point:

Checking core/tests/Drupal/Tests/Composer/fixtures/fake-composer/bin/composer

check failed: file core/tests/Drupal/Tests/Composer/fixtures/fake-composer/bin/composer should not be executable

The core commit check script ensures all files are not executable, so we need an exception or some other way to set this up.

phenaproxima’s picture

The core commit check script ensures all files are not executable, so we need an exception or some other way to set this up.

Okay, refactored the test a bit in the hopes that it will work on CI now.

phenaproxima’s picture

Status: Needs review » Needs work

Is there a case for making this configurable, at least with an on/off flag, for sites that will never use automatic updates and want to retain the existing behaviour?

I think this is already configurable (by putting composer/composer: ['bin'] into the extra.drupal-vendor-hardening section of composer.json), but I should add a test to prove it.

phenaproxima’s picture

Status: Needs work » Needs review
xjm’s picture

Status: Needs review » Needs work
Issue tags: +Needs change record, +Needs release note

I confirmed with @phenaproxima that in HEAD, the binaries are removed entirely, so the change proposed by this issue is adding an internal configuration to make the composer binaries retained and read-only at the given path.

Composer is only a dev dependency for core, not a production one, so this mainly becomes important for sites that have Package Manager enabled (i.e. Composer is a production dependency). If this passes security review, then it's essentially a feature addition of a single internal constant and the binaries.

However, other sites could be affected depending on the sophistication of their deployment workflows. Ideally sites' production builds will be deployed with --no-dev, but we can't be sure this is the case everywhere, so it's a bit dangerous to suddenly have these binaries popping up everywhere in unpredictable situations.

I asked @phenaproxima to consider instead making this an optional configuration that is off by default, but that Drupal CMS (and perhaps later Package Manager itself) enables. That way, it could be backported safely with very little API surface or risk to existing sites, but Drupal CMS could also get access to the configuration immediately. This would also be a security hardening: sites or applications would need to opt into making the binaries available, and they would remain unavailable in the default case for deployments where they are not needed.

This will also need a CR and a release note.

Thanks!

phenaproxima’s picture

Status: Needs work » Needs review

Submitted for your consideration: a way that keeps the status quo very much intact, but also gives Drupal CMS a path forward.

Right now, there is no way to stop a package from being cleaned. The way the plugin is written utterly precludes that. This MR provides such a way: set a package's cleanup paths to false:

"extra": {
  "drupal-core-vendor-hardening": {
    "composer/composer": false
  }
}

If a project sets this up, then composer/composer will not be touched. This approach leaves the default behavior unchanged; without this override, the package will be cleaned as it currently is because the configuration will be the same as it is now.

In other words, existing sites will continue working exactly as they do now with no configuration change required. Drupal CMS will be able to keep Composer's binary around, and will be responsible for taking whatever additional steps are necessary to make it read-only. (Probably a post-update-cmd script that runs a line or two of custom PHP, but that is completely outside the scope of core's concerns.)

This is the most minimal change I could come up with that should (I hope) be eligible for backport, without changing what will happen for new or existing sites.

phenaproxima’s picture

Title: The vendor hardening plugin should not remove Composer's binaries, but just make them read-only » The vendor hardening plugin should provide a way to skip cleaning certain packages
Issue tags: +Needs issue summary update
phenaproxima’s picture

phenaproxima’s picture

Issue tags: -Needs change record
longwave’s picture

Status: Needs review » Needs work
Issue tags: -Needs security review, -Needs release manager review, -no-needs-review-bot

From a security point of view I think this is fine, given it's new behaviour that is explicitly opt-in, so existing sites don't have to change anything. Site owners can do slightly more dangerous things with this feature but that's up to them to configure it and it's not up to us to prevent that.

I don't see any release management issues either given there is little disruption here. The only possible minor disruption is the addition of the File constraint which there is a chance is already used in the wild somewhere, though given this just uses the Symfony constraint it is likely they have made the same implementation anyway. We should add a change record for this just in case.

We should also document this new capability in composer/Plugin/VendorHardening/README.txt, marking NW for that and the CR.

Also removing the bot tag as I think the bot was correct earlier when we had that executable file in the patch, that is gone so the bot should be happy.

phenaproxima’s picture

Status: Needs work » Needs review

Documentation and change record added.

longwave’s picture

Status: Needs review » Reviewed & tested by the community

No further comments, this is as small a change as can be to get this feature in. Marking RTBC for another committer to double check everything.

Agree that this can be backported to 11.2.x so Drupal CMS can make use of it.

phenaproxima’s picture

Committers, please backport this to 11.2.x. 🙏

Doing so will allow this improvement to come to all existing Drupal CMS projects (see #3535731: Require Drupal 11.2.4 and add Composer as a runtime dependency for where that will be done), and it will greatly help new Drupal CMS users get set up with Package Manager (without needing to wait until 11.3.0). The change set is as small as possible to facilitate a clean backport, and I have been explicit about this request since I started talking about it with the release managers. :)

xjm’s picture

When this is committed, remember to tag the issue for the release notes of the correct 11.2.x patch release (which is 11.2.3 as of now).

  • catch committed ce807bf9 on 11.2.x
    Issue #3534278 by phenaproxima, longwave, xjm: The vendor hardening...

  • catch committed e96610e2 on 11.x
    Issue #3534278 by phenaproxima, longwave, xjm: The vendor hardening...

catch’s picture

Version: 11.x-dev » 11.2.x-dev
Status: Reviewed & tested by the community » Fixed
Issue tags: +11.2.3 release notes

I think this looks good and it will help Drupal CMS site a lot.

Committed/pushed to 11.x and cherry-picked to 11.2.x, thanks!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

phenaproxima’s picture

Status: Closed (fixed) » Reviewed & tested by the community

I propose that we recommit this as-is.

It is an opt-in behavior that does not change the current out-of-the-box behavior in any way, nor introduce any new (potentially insecure) default configuration. Drupal CMS could immediately take advantage of it to help our users get set up with Composer more quickly, even without the other changes that were made, and subsequently reverted, in Package Manager. This one is the key.

For that reason, I am tentatively restoring RTBC on the hopes that the release managers and security team will agree with my assessment, although I understand that this was reverted out of a well-reasoned abundance of caution. Depending on how we decide to proceed, it may or may not make sense to revisit this issue, but I am optimistic that this patch will not get in the way of a more holistic, secure way for Package Manager to use a local copy of Composer.

catch’s picture

Status: Reviewed & tested by the community » Needs work

Left a comment on the MR.

phenaproxima’s picture

Status: Needs work » Needs review
Issue tags: -11.2.3 release notes +11.2.4 release notes
pameeela’s picture

Status: Needs review » Reviewed & tested by the community

All seems sensible to me, thanks to all who contributed to making sense of it!

  • catch committed 2ffb26b0 on 11.2.x
    Issue #3534278 by phenaproxima, longwave, xjm, catch: The vendor...

  • catch committed be8698ac on 11.x
    Issue #3534278 by phenaproxima, longwave, xjm, catch: The vendor...
catch’s picture

Status: Reviewed & tested by the community » Fixed

Looks good now without the package manager changes.

Committed/pushed to 11.x and cherry-picked to 11.2.x, thanks!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.