diff --git a/core/modules/package_manager/tests/modules/fixture_manipulator/src/FixtureManipulator.php b/core/modules/package_manager/tests/modules/fixture_manipulator/src/FixtureManipulator.php index a0410cf751430c1a6731b2618163847cbd82be4a..24409a08d93a263cdaaa82653d8b711e95a9d70d 100644 --- a/core/modules/package_manager/tests/modules/fixture_manipulator/src/FixtureManipulator.php +++ b/core/modules/package_manager/tests/modules/fixture_manipulator/src/FixtureManipulator.php @@ -303,8 +303,10 @@ public function setCorePackageVersion(string $version): self { * * @param array $additional_config * The configuration to add. + * @param bool $update_lock + * Whether to run composer update --lock. Defaults to FALSE. */ - public function addConfig(array $additional_config): self { + public function addConfig(array $additional_config, bool $update_lock = FALSE): self { if (empty($additional_config)) { throw new \InvalidArgumentException('No config to add.'); } @@ -330,7 +332,9 @@ public function addConfig(array $additional_config): self { $command[] = $value; $this->runComposerCommand($command); } - $this->runComposerCommand(['update', '--lock']); + if ($update_lock) { + $this->runComposerCommand(['update', '--lock']); + } return $this; } @@ -348,8 +352,10 @@ public function commitChanges(string $dir): void { * * @param string $dir * The directory to commit the changes to. + * @param bool $validate_composer + * Whether to run composer validate or not. */ - final protected function doCommitChanges(string $dir): void { + final protected function doCommitChanges(string $dir, $validate_composer = FALSE): void { if ($this->committed) { throw new \BadMethodCallException('Already committed.'); } @@ -367,7 +373,9 @@ final protected function doCommitChanges(string $dir): void { } $this->committed = TRUE; $this->committingChanges = FALSE; - $this->validateComposer(); + if ($validate_composer) { + $this->validateComposer(); + } } /** @@ -623,8 +631,12 @@ private function addRepository(array $package): string { /** * Sets up the path repos at absolute paths. + * + * @param bool $composer_refresh + * Whether to run composer update --lock && composer install. Defaults to + * FALSE. */ - public function setUpRepos(): void { + public function setUpRepos($composer_refresh = FALSE): void { $fs = new SymfonyFileSystem(); $path_repo_base = \Drupal::state()->get(self::PATH_REPO_STATE_KEY); if (empty($path_repo_base)) { @@ -638,8 +650,10 @@ public function setUpRepos(): void { // repos at the absolute path. $composer_json = file_get_contents($this->dir . '/packages.json'); assert(file_put_contents($this->dir . '/packages.json', str_replace('../path_repos/', "$path_repo_base/", $composer_json)) !== FALSE); - $this->runComposerCommand(['update', '--lock']); - $this->runComposerCommand(['install']); + if ($composer_refresh) { + $this->runComposerCommand(['update', '--lock']); + $this->runComposerCommand(['install']); + } } } diff --git a/core/modules/package_manager/tests/src/Kernel/ComposerPluginsValidatorInsecureTest.php b/core/modules/package_manager/tests/src/Kernel/ComposerPluginsValidatorInsecureTest.php new file mode 100644 index 0000000000000000000000000000000000000000..0912f7b6e712dd79b68c44e04b8a2e805c66221b --- /dev/null +++ b/core/modules/package_manager/tests/src/Kernel/ComposerPluginsValidatorInsecureTest.php @@ -0,0 +1,97 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\Tests\package_manager\Kernel; + +use Drupal\Core\StringTranslation\TranslatableMarkup; +use Drupal\fixture_manipulator\ActiveFixtureManipulator; +use Drupal\package_manager\Event\PreApplyEvent; +use Drupal\package_manager\Event\PreCreateEvent; +use Drupal\package_manager\Exception\StageEventException; +use Drupal\package_manager\ValidationResult; + +/** + * @covers \Drupal\package_manager\Validator\ComposerPluginsValidator + * @group package_manager + * @internal + */ +class ComposerPluginsValidatorInsecureTest extends PackageManagerKernelTestBase { + + /** + * Tests `config.allow-plugins: true` fails validation during pre-create. + */ + public function testInsecureConfigurationFailsValidationPreCreate(): void { + $active_manipulator = new ActiveFixtureManipulator(); + $active_manipulator->addConfig(['allow-plugins' => TRUE]); + $active_manipulator->commitChanges(); + + $expected_results = [ + ValidationResult::createError( + [ + new TranslatableMarkup('All composer plugins are allowed because <code>config.allow-plugins</code> is configured to <code>true</code>. This is an unacceptable security risk.'), + ], + ), + ]; + $this->assertStatusCheckResults($expected_results); + $this->assertResults($expected_results, PreCreateEvent::class); + } + + /** + * Tests `config.allow-plugins: true` fails validation during pre-apply. + */ + public function testInsecureConfigurationFailsValidationPreApply(): void { + $stage_manipulator = $this->getStageFixtureManipulator(); + $stage_manipulator->addConfig(['allow-plugins' => TRUE]); + + $expected_results = [ + ValidationResult::createError( + [ + new TranslatableMarkup('All composer plugins are allowed because <code>config.allow-plugins</code> is configured to <code>true</code>. This is an unacceptable security risk.'), + ], + ), + ]; + $this->assertResults($expected_results, PreApplyEvent::class); + } + + /** + * Tests adding a plugin that's not allowed by the allow-plugins config. + * + * The exception that this test looks for is not necessarily triggered by + * ComposerPluginsValidator; Composer will exit with an error if there is an + * installed plugin that is not allowed by the `allow-plugins` config. In + * practice, this means that whichever validator is the first one to do a + * Composer operation (via ComposerInspector) will get the exception -- it + * may or may not be ComposerPluginsValidator. + * + * This test is here to ensure that Composer's behavior remains consistent, + * even if we're not explicitly testing ComposerPluginsValidator here. + */ + public function testAddDisallowedPlugin(): void { + $this->getStageFixtureManipulator() + ->addPackage([ + 'name' => 'composer/plugin-c', + 'version' => '16.4', + 'type' => 'composer-plugin', + 'require' => ['composer-plugin-api' => '*'], + 'extra' => ['class' => 'AnyClass'], + ]); + + $expected_message = "composer/plugin-c contains a Composer plugin which is blocked by your allow-plugins config."; + $stage = $this->createStage(); + $stage->create(); + $stage->require(['drupal/core:9.8.1']); + try { + // We are trying to add package plugin-c but not allowing it in config, + // so we expect the operation to fail on PreApplyEvent. + $stage->apply(); + } + catch (StageEventException $e) { + // Processing is required because the error message we get from Composer + // contains multiple white spaces at the start or end of line. + $this->assertStringContainsString($expected_message, preg_replace('/\s\s+/', '', $e->getMessage())); + $this->assertInstanceOf(PreApplyEvent::class, $e->event); + } + } + +} diff --git a/core/modules/package_manager/tests/src/Kernel/ComposerPluginsValidatorTest.php b/core/modules/package_manager/tests/src/Kernel/ComposerPluginsValidatorTest.php index cf3c0638ed730d87cd4e759b23b6a8ae45d08c31..12a693db70f57357f979b8f361ecdf3515cad7bd 100644 --- a/core/modules/package_manager/tests/src/Kernel/ComposerPluginsValidatorTest.php +++ b/core/modules/package_manager/tests/src/Kernel/ComposerPluginsValidatorTest.php @@ -9,7 +9,6 @@ use Drupal\fixture_manipulator\ActiveFixtureManipulator; use Drupal\package_manager\Event\PreApplyEvent; use Drupal\package_manager\Event\PreCreateEvent; -use Drupal\package_manager\Exception\StageEventException; use Drupal\package_manager\ValidationResult; /** @@ -19,42 +18,6 @@ */ class ComposerPluginsValidatorTest extends PackageManagerKernelTestBase { - /** - * Tests `config.allow-plugins: true` fails validation during pre-create. - */ - public function testInsecureConfigurationFailsValidationPreCreate(): void { - $active_manipulator = new ActiveFixtureManipulator(); - $active_manipulator->addConfig(['allow-plugins' => TRUE]); - $active_manipulator->commitChanges(); - - $expected_results = [ - ValidationResult::createError( - [ - new TranslatableMarkup('All composer plugins are allowed because <code>config.allow-plugins</code> is configured to <code>true</code>. This is an unacceptable security risk.'), - ], - ), - ]; - $this->assertStatusCheckResults($expected_results); - $this->assertResults($expected_results, PreCreateEvent::class); - } - - /** - * Tests `config.allow-plugins: true` fails validation during pre-apply. - */ - public function testInsecureConfigurationFailsValidationPreApply(): void { - $stage_manipulator = $this->getStageFixtureManipulator(); - $stage_manipulator->addConfig(['allow-plugins' => TRUE]); - - $expected_results = [ - ValidationResult::createError( - [ - new TranslatableMarkup('All composer plugins are allowed because <code>config.allow-plugins</code> is configured to <code>true</code>. This is an unacceptable security risk.'), - ], - ), - ]; - $this->assertResults($expected_results, PreApplyEvent::class); - } - /** * Tests composer plugins are validated during pre-create. * @@ -102,46 +65,6 @@ public function testValidationDuringPreApply(array $composer_config_to_add, arra $this->assertResults($expected_results, PreApplyEvent::class); } - /** - * Tests adding a plugin that's not allowed by the allow-plugins config. - * - * The exception that this test looks for is not necessarily triggered by - * ComposerPluginsValidator; Composer will exit with an error if there is an - * installed plugin that is not allowed by the `allow-plugins` config. In - * practice, this means that whichever validator is the first one to do a - * Composer operation (via ComposerInspector) will get the exception -- it - * may or may not be ComposerPluginsValidator. - * - * This test is here to ensure that Composer's behavior remains consistent, - * even if we're not explicitly testing ComposerPluginsValidator here. - */ - public function testAddDisallowedPlugin(): void { - $this->getStageFixtureManipulator() - ->addPackage([ - 'name' => 'composer/plugin-c', - 'version' => '16.4', - 'type' => 'composer-plugin', - 'require' => ['composer-plugin-api' => '*'], - 'extra' => ['class' => 'AnyClass'], - ]); - - $expected_message = "composer/plugin-c contains a Composer plugin which is blocked by your allow-plugins config."; - $stage = $this->createStage(); - $stage->create(); - $stage->require(['drupal/core:9.8.1']); - try { - // We are trying to add package plugin-c but not allowing it in config, - // so we expect the operation to fail on PreApplyEvent. - $stage->apply(); - } - catch (StageEventException $e) { - // Processing is required because the error message we get from Composer - // contains multiple white spaces at the start or end of line. - $this->assertStringContainsString($expected_message, preg_replace('/\s\s+/', '', $e->getMessage())); - $this->assertInstanceOf(PreApplyEvent::class, $e->event); - } - } - /** * Tests additional composer plugins can be trusted during pre-create. *