Skip to content
Snippets Groups Projects
Commit 3efd96d8 authored by Rahul Gupta's avatar Rahul Gupta Committed by Adam G-H
Browse files

Issue #3310901 by rahul_, phenaproxima, TravisCarden: Stage::require() should...

Issue #3310901 by rahul_, phenaproxima, TravisCarden: Stage::require() should validate the incoming package names
parent 07da6ecc
No related branches found
No related tags found
No related merge requests found
......@@ -356,10 +356,12 @@ class Stage implements LoggerAwareInterface {
// Change the runtime and dev requirements as needed, but don't update
// the installed packages yet.
if ($runtime) {
$this->validatePackageNames($runtime);
$command = array_merge(['require', '--no-update'], $runtime);
$this->stager->stage($command, $active_dir, $stage_dir, NULL, $timeout);
}
if ($dev) {
$this->validatePackageNames($dev);
$command = array_merge(['require', '--dev', '--no-update'], $dev);
$this->stager->stage($command, $active_dir, $stage_dir, NULL, $timeout);
}
......@@ -705,4 +707,35 @@ class Stage implements LoggerAwareInterface {
return $this->t('Staged changes failed to apply, and the site is in an indeterminate state. It is strongly recommended to restore the code and database from a backup.');
}
/**
* Validates a set of package names.
*
* Package names are considered invalid if they look like Drupal project
* names. The only exceptions to this are `php` and `composer`, which Composer
* treats as legitimate requirements.
*
* @param string[] $package_versions
* A set of package names (with or without version constraints), as passed
* to ::require().
*
* @throws \InvalidArgumentException
* Thrown if any of the given package names are invalid.
*
* @see https://getcomposer.org/doc/articles/composer-platform-dependencies.md
*/
protected function validatePackageNames(array $package_versions): void {
foreach ($package_versions as $package_name) {
$package_name = trim($package_name);
// Don't mistake the legitimate `php` and `composer` platform requirements
// for Drupal projects.
if ($package_name === 'php' || $package_name === 'composer') {
continue;
}
elseif (preg_match('/^[a-z0-9_]+$/i', $package_name)) {
throw new \InvalidArgumentException("Invalid package name '$package_name'.");
}
}
}
}
......@@ -51,7 +51,7 @@ class OverwriteExistingPackagesValidatorTest extends PackageManagerKernelTestBas
$stage = $this->createStage();
$stage->create();
$stage->require(['drupal' => '9.8.1']);
$stage->require(['drupal/core:9.8.1']);
$expected_results = [
ValidationResult::createError([
......
......@@ -300,7 +300,7 @@ class StageTest extends PackageManagerKernelTestBase {
public function testCommitException(string $thrown_class, string $expected_class): void {
$stage = $this->createStage();
$stage->create();
$stage->require(['drupal/core' => '9.8.1']);
$stage->require(['drupal/core:9.8.1']);
$thrown_message = 'A very bad thing happened';
// PreconditionException requires a preconditions object.
......@@ -421,7 +421,7 @@ class StageTest extends PackageManagerKernelTestBase {
// Run apply and post-apply in the same request (i.e., the same request
// time), and ensure the warning is logged.
$stage->create();
$stage->require(['drupal/core' => '9.8.1']);
$stage->require(['drupal/core:9.8.1']);
$stage->apply();
$stage->postApply();
$this->assertTrue($logger->hasRecord($warning_message, LogLevel::WARNING));
......@@ -429,7 +429,7 @@ class StageTest extends PackageManagerKernelTestBase {
$logger->reset();
$stage->create();
$stage->require(['drupal/core' => '9.8.2']);
$stage->require(['drupal/core:9.8.2']);
$stage->apply();
// Simulate post-apply taking place in another request by simulating a
// request time 30 seconds after apply started.
......@@ -438,6 +438,60 @@ class StageTest extends PackageManagerKernelTestBase {
$this->assertFalse($logger->hasRecord($warning_message, LogLevel::WARNING));
}
/**
* @covers ::validatePackageNames
*
* @param string $package_name
* The package name.
* @param bool $is_invalid
* TRUE if the gien package name is invalid and will cause an exception,
* FALSE otherwise.
*
* @dataProvider providerValidatePackageNames
*/
public function testValidatePackageNames(string $package_name, bool $is_invalid): void {
$stage = $this->createStage();
$stage->create();
if ($is_invalid) {
$this->expectException('InvalidArgumentException');
$this->expectExceptionMessage("Invalid package name '$package_name'.");
}
$stage->require([$package_name]);
// If we got here, the package name is valid and we just need to assert something so PHPUnit doesn't complain.
$this->assertTrue(TRUE);
}
/**
* Data provider for testValidatePackageNames.
*
* @return array[]
* The test cases.
*/
public function providerValidatePackageNames(): array {
return [
// White space is trimmed out of package names during validation.
'empty string' => ['', FALSE],
'white space' => [' ', FALSE],
// The `composer` and `php` requirements are special, since they could
// otherwise be mistaken for Drupal project names.
'Composer runtime, unconstrained' => ['composer', FALSE],
'Composer runtime, constrained' => ['composer:^2.4', FALSE],
'Composer runtime API, unconstrained' => ['composer-runtime-api', FALSE],
'Composer runtime API, constrained' => ['composer-runtime-api:~2.2.0', FALSE],
'PHP runtime, unconstrained' => ['php', FALSE],
'PHP runtime, constrained' => ['php:>=7.4', FALSE],
'PHP runtime variant, unconstrained' => ['php-zts', FALSE],
'PHP runtime variant, constrained' => ['php-zts:8.1', FALSE],
'PHP extension, unconstrained' => ['ext-json', FALSE],
'PHP extension, constrained' => ['ext-json:7.4.1', FALSE],
'PHP library, unconstrained' => ['lib-curl', FALSE],
'PHP library, constrained' => ['lib-curl:^7', FALSE],
'Drupal package, unconstrained' => ['drupal/semver_test', FALSE],
'Drupal package, constrained' => ['drupal/semver_test:^1.10', FALSE],
'Drupal project' => ['semver_test', TRUE],
];
}
}
/**
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment