Skip to content
Snippets Groups Projects
Commit 42ad7d56 authored by Ted Bowman's avatar Ted Bowman Committed by Adam G-H
Browse files

Issue #3271468 by tedbow, phenaproxima: Validate the target version is secure and supported

parent ece5a5f4
No related branches found
No related tags found
No related merge requests found
...@@ -129,3 +129,7 @@ services: ...@@ -129,3 +129,7 @@ services:
- '@string_translation' - '@string_translation'
tags: tags:
- { name: event_subscriber } - { name: event_subscriber }
automatic_updates.validator.target_release:
class: \Drupal\automatic_updates\Validator\UpdateReleaseValidator
tags:
- { name: event_subscriber }
<?php
namespace Drupal\automatic_updates\Validator;
use Drupal\automatic_updates\ProjectInfo;
use Drupal\automatic_updates\Updater;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\package_manager\Event\PreCreateEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* Validates that the target release of Drupal core is secure and supported.
*/
class UpdateReleaseValidator implements EventSubscriberInterface {
use StringTranslationTrait;
/**
* Checks that the target version of Drupal core is secure and supported.
*
* @param \Drupal\package_manager\Event\PreCreateEvent $event
* The event object.
*/
public function checkRelease(PreCreateEvent $event): void {
$stage = $event->getStage();
// This check only works with Automatic Updates.
if (!$stage instanceof Updater) {
return;
}
$package_versions = $stage->getPackageVersions();
// The updater will only update Drupal core, so all production dependencies
// will be Drupal core packages.
$target_version = reset($package_versions['production']);
// If the target version isn't in the list of installable releases, then it
// isn't secure and supported and we should flag an error.
$releases = (new ProjectInfo('drupal'))->getInstallableReleases();
if (empty($releases) || !array_key_exists($target_version, $releases)) {
$message = $this->t('Cannot update Drupal core to @target_version because it is not in the list of installable releases.', [
'@target_version' => $target_version,
]);
$event->addError([$message]);
}
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents() {
return [
PreCreateEvent::class => 'checkRelease',
];
}
}
...@@ -219,12 +219,8 @@ class ReadinessValidationManagerTest extends AutomaticUpdatesKernelTestBase { ...@@ -219,12 +219,8 @@ class ReadinessValidationManagerTest extends AutomaticUpdatesKernelTestBase {
* Tests that stored validation results are deleted after an update. * Tests that stored validation results are deleted after an update.
*/ */
public function testStoredResultsDeletedPostApply(): void { public function testStoredResultsDeletedPostApply(): void {
$this->container->get('module_installer') $this->enableModules(['automatic_updates']);
->install(['automatic_updates']);
// Ensure there's a simulated core release to update to.
$this->setCoreVersion('9.8.1'); $this->setCoreVersion('9.8.1');
$this->setReleaseMetadata(__DIR__ . '/../../../fixtures/release-history/drupal.9.8.2.xml');
// The readiness checker should raise a warning, so that the update is not // The readiness checker should raise a warning, so that the update is not
// blocked or aborted. // blocked or aborted.
......
...@@ -51,7 +51,7 @@ class SettingsValidatorTest extends AutomaticUpdatesKernelTestBase { ...@@ -51,7 +51,7 @@ class SettingsValidatorTest extends AutomaticUpdatesKernelTestBase {
$this->assertCheckerResultsFromManager($expected_results, TRUE); $this->assertCheckerResultsFromManager($expected_results, TRUE);
try { try {
$this->container->get('automatic_updates.updater')->begin([ $this->container->get('automatic_updates.updater')->begin([
'drupal' => '9.8.1', 'drupal' => '9.8.2',
]); ]);
// If there was no exception, ensure we're not expecting any errors. // If there was no exception, ensure we're not expecting any errors.
$this->assertSame([], $expected_results); $this->assertSame([], $expected_results);
......
...@@ -61,7 +61,7 @@ class StagedProjectsValidatorTest extends AutomaticUpdatesKernelTestBase { ...@@ -61,7 +61,7 @@ class StagedProjectsValidatorTest extends AutomaticUpdatesKernelTestBase {
} }
$updater = $this->container->get('automatic_updates.updater'); $updater = $this->container->get('automatic_updates.updater');
$stage_id = $updater->begin(['drupal' => '9.8.1']); $stage_id = $updater->begin(['drupal' => '9.8.2']);
if ($stage_dir_exists) { if ($stage_dir_exists) {
// Copy the fixture's staging directory into a subdirectory using the // Copy the fixture's staging directory into a subdirectory using the
// stage ID as the directory name. // stage ID as the directory name.
......
<?php
namespace Drupal\Tests\automatic_updates\Kernel\ReadinessValidation;
use Drupal\automatic_updates\Exception\UpdateException;
use Drupal\package_manager\ValidationResult;
use Drupal\Tests\automatic_updates\Kernel\AutomaticUpdatesKernelTestBase;
/**
* @covers \Drupal\automatic_updates\Validator\UpdateReleaseValidator
*
* @group automatic_updates
*/
class UpdateReleaseValidatorTest extends AutomaticUpdatesKernelTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = ['automatic_updates'];
/**
* Tests that an error is raised when trying to update to an unknown release.
*/
public function testUnknownReleaseRaisesError(): void {
$result = ValidationResult::createError([
'Cannot update Drupal core to 9.8.99 because it is not in the list of installable releases.',
]);
try {
$this->container->get('automatic_updates.updater')->begin([
'drupal' => '9.8.99',
]);
$this->fail('Expected an exception to be thrown, but it was not.');
}
catch (UpdateException $e) {
$this->assertValidationResultsEqual([$result], $e->getResults());
}
}
}
...@@ -34,6 +34,9 @@ class UpdaterTest extends AutomaticUpdatesKernelTestBase { ...@@ -34,6 +34,9 @@ class UpdaterTest extends AutomaticUpdatesKernelTestBase {
* Tests that correct versions are staged after calling ::begin(). * Tests that correct versions are staged after calling ::begin().
*/ */
public function testCorrectVersionsStaged(): void { public function testCorrectVersionsStaged(): void {
// Simulate that we're running Drupal 9.8.0 and a security update to 9.8.1
// is available.
$this->setCoreVersion('9.8.0');
$this->setReleaseMetadata(__DIR__ . '/../../fixtures/release-history/drupal.9.8.1-security.xml'); $this->setReleaseMetadata(__DIR__ . '/../../fixtures/release-history/drupal.9.8.1-security.xml');
// Create a user who will own the stage even after the container is rebuilt. // Create a user who will own the stage even after the container is rebuilt.
......
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