Skip to content
Snippets Groups Projects
Commit f083a92b authored by Kunal Sachdev's avatar Kunal Sachdev Committed by Adam G-H
Browse files

Issue #3265874 by kunal.sachdev, phenaproxima: Do not allow apply if active...

Issue #3265874 by kunal.sachdev, phenaproxima: Do not allow apply if active and staged composer locks are identical
parent 85b969d9
No related branches found
No related tags found
1 merge request!227Issue #3265874: Do not allow apply if active and staged composer locks are identical.
...@@ -57,14 +57,17 @@ class LockFileValidator implements PreOperationStageValidatorInterface { ...@@ -57,14 +57,17 @@ class LockFileValidator implements PreOperationStageValidatorInterface {
} }
/** /**
* Returns the current hash of the active directory's lock file. * Returns the current hash of the given directory's lock file.
*
* @param string $directory
* Path of a directory containing a composer.lock file.
* *
* @return string|false * @return string|false
* The hash of the active directory's lock file, or FALSE if the lock file * The hash of the given directory's lock file, or FALSE if the lock file
* does not exist. * does not exist.
*/ */
protected function getHash() { protected function getLockFileHash(string $directory) {
$file = $this->pathLocator->getProjectRoot() . DIRECTORY_SEPARATOR . 'composer.lock'; $file = $directory . DIRECTORY_SEPARATOR . 'composer.lock';
// We want to directly hash the lock file itself, rather than look at its // We want to directly hash the lock file itself, rather than look at its
// content-hash value, which is actually a hash of the relevant parts of // content-hash value, which is actually a hash of the relevant parts of
// composer.json. We're trying to verify that the actual installed packages // composer.json. We're trying to verify that the actual installed packages
...@@ -81,7 +84,7 @@ class LockFileValidator implements PreOperationStageValidatorInterface { ...@@ -81,7 +84,7 @@ class LockFileValidator implements PreOperationStageValidatorInterface {
* Stores the current lock file hash. * Stores the current lock file hash.
*/ */
public function storeHash(PreCreateEvent $event): void { public function storeHash(PreCreateEvent $event): void {
$hash = $this->getHash(); $hash = $this->getLockFileHash($this->pathLocator->getProjectRoot());
if ($hash) { if ($hash) {
$this->state->set(static::STATE_KEY, $hash); $this->state->set(static::STATE_KEY, $hash);
} }
...@@ -97,8 +100,8 @@ class LockFileValidator implements PreOperationStageValidatorInterface { ...@@ -97,8 +100,8 @@ class LockFileValidator implements PreOperationStageValidatorInterface {
*/ */
public function validateStagePreOperation(PreOperationStageEvent $event): void { public function validateStagePreOperation(PreOperationStageEvent $event): void {
// Ensure we can get a current hash of the lock file. // Ensure we can get a current hash of the lock file.
$hash = $this->getHash(); $active_hash = $this->getLockFileHash($this->pathLocator->getProjectRoot());
if (empty($hash)) { if (empty($active_hash)) {
$error = $this->t('Could not hash the active lock file.'); $error = $this->t('Could not hash the active lock file.');
} }
...@@ -109,10 +112,19 @@ class LockFileValidator implements PreOperationStageValidatorInterface { ...@@ -109,10 +112,19 @@ class LockFileValidator implements PreOperationStageValidatorInterface {
} }
// If we have both hashes, ensure they match. // If we have both hashes, ensure they match.
if ($hash && $stored_hash && !hash_equals($stored_hash, $hash)) { if ($active_hash && $stored_hash && !hash_equals($stored_hash, $active_hash)) {
$error = $this->t('Stored lock file hash does not match the active lock file.'); $error = $this->t('Stored lock file hash does not match the active lock file.');
} }
// Don't allow staged changes to be applied if the staged lock file has no
// apparent changes.
if (empty($error) && $event instanceof PreApplyEvent) {
$stage_hash = $this->getLockFileHash($event->getStage()->getStageDirectory());
if ($stage_hash && hash_equals($active_hash, $stage_hash)) {
$error = $this->t('There are no pending Composer operations.');
}
}
// @todo Let the validation result carry all the relevant messages in // @todo Let the validation result carry all the relevant messages in
// https://www.drupal.org/i/3247479. // https://www.drupal.org/i/3247479.
if (isset($error)) { if (isset($error)) {
......
...@@ -14,6 +14,17 @@ use Drupal\package_manager\EventSubscriber\ExcludedPathsSubscriber; ...@@ -14,6 +14,17 @@ use Drupal\package_manager\EventSubscriber\ExcludedPathsSubscriber;
*/ */
class ExcludedPathsTest extends PackageManagerKernelTestBase { class ExcludedPathsTest extends PackageManagerKernelTestBase {
/**
* {@inheritdoc}
*/
protected function setUp(): void {
// In this test, we want to disable the lock file validator because, even
// though both the active and stage directories will have a valid lock file,
// this validator will complain because they don't differ at all.
$this->disableValidators[] = 'package_manager.validator.lock_file';
parent::setUp();
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
namespace Drupal\Tests\package_manager\Kernel; namespace Drupal\Tests\package_manager\Kernel;
use Drupal\package_manager\Event\PostRequireEvent;
use Drupal\package_manager\Event\PreApplyEvent; use Drupal\package_manager\Event\PreApplyEvent;
use Drupal\package_manager\Event\PreCreateEvent; use Drupal\package_manager\Event\PreCreateEvent;
use Drupal\package_manager\Event\PreRequireEvent; use Drupal\package_manager\Event\PreRequireEvent;
...@@ -119,6 +120,21 @@ class LockFileValidatorTest extends PackageManagerKernelTestBase { ...@@ -119,6 +120,21 @@ class LockFileValidatorTest extends PackageManagerKernelTestBase {
$this->assertResults([$result], $event_class); $this->assertResults([$result], $event_class);
} }
/**
* Tests validation when the staged and active lock files are identical.
*/
public function testApplyWithNoChange(): void {
$this->addListener(PostRequireEvent::class, function (PostRequireEvent $event) {
$stage_dir = $event->getStage()->getStageDirectory();
mkdir($stage_dir);
copy("$this->activeDir/composer.lock", "$stage_dir/composer.lock");
});
$result = ValidationResult::createError([
'There are no pending Composer operations.',
]);
$this->assertResults([$result], PreApplyEvent::class);
}
/** /**
* Data provider for test methods that validate the staging area. * Data provider for test methods that validate the staging area.
* *
......
...@@ -40,6 +40,10 @@ abstract class AutomaticUpdatesFunctionalTestBase extends BrowserTestBase { ...@@ -40,6 +40,10 @@ abstract class AutomaticUpdatesFunctionalTestBase extends BrowserTestBase {
// package_manager_bypass is disabling those operations. // package_manager_bypass is disabling those operations.
'automatic_updates.composer_executable_validator', 'automatic_updates.composer_executable_validator',
'package_manager.validator.composer_executable', 'package_manager.validator.composer_executable',
// Disable the lock file validator, because it may cause the tests to fail
// if either the active and stage directories don't have a composer.lock
// file, which is the case with some of our fixtures.
'package_manager.validator.lock_file',
]; ];
/** /**
......
...@@ -30,6 +30,10 @@ class StagedDatabaseUpdateValidatorTest extends AutomaticUpdatesKernelTestBase { ...@@ -30,6 +30,10 @@ class StagedDatabaseUpdateValidatorTest extends AutomaticUpdatesKernelTestBase {
* {@inheritdoc} * {@inheritdoc}
*/ */
protected function setUp(): void { protected function setUp(): void {
// In this test, we want to disable the lock file validator because, even
// though both the active and stage directories will have a valid lock file,
// this validator will complain because they don't differ at all.
$this->disableValidators[] = 'package_manager.validator.lock_file';
parent::setUp(); parent::setUp();
TestStage::$stagingRoot = $this->vfsRoot->url(); TestStage::$stagingRoot = $this->vfsRoot->url();
......
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