Add the hash of the parsed content of the composer.json to the lock file, and use it to verify the json is not changed
parent
89540c5690
commit
50b560fe4c
|
@ -306,7 +306,7 @@ class Factory
|
|||
$lockFile = "json" === pathinfo($composerFile, PATHINFO_EXTENSION)
|
||||
? substr($composerFile, 0, -4).'lock'
|
||||
: $composerFile . '.lock';
|
||||
$locker = new Package\Locker($io, new JsonFile($lockFile, new RemoteFilesystem($io, $config)), $rm, $im, md5_file($composerFile));
|
||||
$locker = new Package\Locker($io, new JsonFile($lockFile, new RemoteFilesystem($io, $config)), $rm, $im, md5_file($composerFile), $this->getContentHash($composerFile));
|
||||
$composer->setLocker($locker);
|
||||
}
|
||||
|
||||
|
@ -485,4 +485,18 @@ class Factory
|
|||
|
||||
return $factory->createComposer($io, $config, $disablePlugins);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the md5 hash of the sorted content of the composer file.
|
||||
*
|
||||
* @param string $composerFilePath Path to the composer file.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getContentHash($composerFilePath)
|
||||
{
|
||||
$content = json_decode(file_get_contents($composerFilePath), true);
|
||||
ksort($content);
|
||||
return md5(json_encode($content));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ class Locker
|
|||
private $repositoryManager;
|
||||
private $installationManager;
|
||||
private $hash;
|
||||
private $contentHash;
|
||||
private $loader;
|
||||
private $dumper;
|
||||
private $process;
|
||||
|
@ -48,13 +49,15 @@ class Locker
|
|||
* @param RepositoryManager $repositoryManager repository manager instance
|
||||
* @param InstallationManager $installationManager installation manager instance
|
||||
* @param string $hash unique hash of the current composer configuration
|
||||
* @param string $contentHash unique hash of the content of the current composer configuration
|
||||
*/
|
||||
public function __construct(IOInterface $io, JsonFile $lockFile, RepositoryManager $repositoryManager, InstallationManager $installationManager, $hash)
|
||||
public function __construct(IOInterface $io, JsonFile $lockFile, RepositoryManager $repositoryManager, InstallationManager $installationManager, $hash, $contentHash)
|
||||
{
|
||||
$this->lockFile = $lockFile;
|
||||
$this->repositoryManager = $repositoryManager;
|
||||
$this->installationManager = $installationManager;
|
||||
$this->hash = $hash;
|
||||
$this->contentHash = $contentHash;
|
||||
$this->loader = new ArrayLoader(null, true);
|
||||
$this->dumper = new ArrayDumper();
|
||||
$this->process = new ProcessExecutor($io);
|
||||
|
@ -85,6 +88,11 @@ class Locker
|
|||
{
|
||||
$lock = $this->lockFile->read();
|
||||
|
||||
if (!empty($lock['content-hash'])) {
|
||||
// There is a content hash key, use that instead of the file hash
|
||||
return $this->contentHash == $lock['content-hash'];
|
||||
}
|
||||
|
||||
return $this->hash === $lock['hash'];
|
||||
}
|
||||
|
||||
|
@ -241,6 +249,7 @@ class Locker
|
|||
'Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file',
|
||||
'This file is @gener'.'ated automatically'),
|
||||
'hash' => $this->hash,
|
||||
'content-hash' => $this->contentHash,
|
||||
'packages' => null,
|
||||
'packages-dev' => null,
|
||||
'aliases' => array(),
|
||||
|
|
|
@ -191,7 +191,8 @@ class InstallerTest extends TestCase
|
|||
}));
|
||||
}
|
||||
|
||||
$locker = new Locker($io, $lockJsonMock, $repositoryManager, $composer->getInstallationManager(), md5(json_encode($composerConfig)));
|
||||
$hash = md5(json_encode($composerConfig));
|
||||
$locker = new Locker($io, $lockJsonMock, $repositoryManager, $composer->getInstallationManager(), $hash, $hash);
|
||||
$composer->setLocker($locker);
|
||||
|
||||
$eventDispatcher = $this->getMockBuilder('Composer\EventDispatcher\EventDispatcher')->disableOriginalConstructor()->getMock();
|
||||
|
@ -237,6 +238,7 @@ class InstallerTest extends TestCase
|
|||
|
||||
if ($expectLock) {
|
||||
unset($actualLock['hash']);
|
||||
unset($actualLock['content-hash']);
|
||||
unset($actualLock['_readme']);
|
||||
$this->assertEquals($expectLock, $actualLock);
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ class LockerTest extends \PHPUnit_Framework_TestCase
|
|||
public function testIsLocked()
|
||||
{
|
||||
$json = $this->createJsonFileMock();
|
||||
$locker = new Locker(new NullIO, $json, $this->createRepositoryManagerMock(), $this->createInstallationManagerMock(), 'md5');
|
||||
$locker = new Locker(new NullIO, $json, $this->createRepositoryManagerMock(), $this->createInstallationManagerMock(), 'md5', 'contentMd5');
|
||||
|
||||
$json
|
||||
->expects($this->any())
|
||||
|
@ -40,7 +40,7 @@ class LockerTest extends \PHPUnit_Framework_TestCase
|
|||
$repo = $this->createRepositoryManagerMock();
|
||||
$inst = $this->createInstallationManagerMock();
|
||||
|
||||
$locker = new Locker(new NullIO, $json, $repo, $inst, 'md5');
|
||||
$locker = new Locker(new NullIO, $json, $repo, $inst, 'md5', 'contentMd5');
|
||||
|
||||
$json
|
||||
->expects($this->once())
|
||||
|
@ -58,7 +58,7 @@ class LockerTest extends \PHPUnit_Framework_TestCase
|
|||
$repo = $this->createRepositoryManagerMock();
|
||||
$inst = $this->createInstallationManagerMock();
|
||||
|
||||
$locker = new Locker(new NullIO, $json, $repo, $inst, 'md5');
|
||||
$locker = new Locker(new NullIO, $json, $repo, $inst, 'md5', 'contentMd5');
|
||||
|
||||
$json
|
||||
->expects($this->once())
|
||||
|
@ -85,7 +85,7 @@ class LockerTest extends \PHPUnit_Framework_TestCase
|
|||
$repo = $this->createRepositoryManagerMock();
|
||||
$inst = $this->createInstallationManagerMock();
|
||||
|
||||
$locker = new Locker(new NullIO, $json, $repo, $inst, 'md5');
|
||||
$locker = new Locker(new NullIO, $json, $repo, $inst, 'md5', 'contentMd5');
|
||||
|
||||
$package1 = $this->createPackageMock();
|
||||
$package2 = $this->createPackageMock();
|
||||
|
@ -124,6 +124,7 @@ class LockerTest extends \PHPUnit_Framework_TestCase
|
|||
'Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file',
|
||||
'This file is @gener'.'ated automatically'),
|
||||
'hash' => 'md5',
|
||||
'content-hash' => 'contentMd5',
|
||||
'packages' => array(
|
||||
array('name' => 'pkg1', 'version' => '1.0.0-beta'),
|
||||
array('name' => 'pkg2', 'version' => '0.1.10')
|
||||
|
@ -148,7 +149,7 @@ class LockerTest extends \PHPUnit_Framework_TestCase
|
|||
$repo = $this->createRepositoryManagerMock();
|
||||
$inst = $this->createInstallationManagerMock();
|
||||
|
||||
$locker = new Locker(new NullIO, $json, $repo, $inst, 'md5');
|
||||
$locker = new Locker(new NullIO, $json, $repo, $inst, 'md5', 'md5');
|
||||
|
||||
$package1 = $this->createPackageMock();
|
||||
$package1
|
||||
|
@ -167,7 +168,7 @@ class LockerTest extends \PHPUnit_Framework_TestCase
|
|||
$repo = $this->createRepositoryManagerMock();
|
||||
$inst = $this->createInstallationManagerMock();
|
||||
|
||||
$locker = new Locker(new NullIO, $json, $repo, $inst, 'md5');
|
||||
$locker = new Locker(new NullIO, $json, $repo, $inst, 'md5', 'contentMd5');
|
||||
|
||||
$json
|
||||
->expects($this->once())
|
||||
|
@ -183,7 +184,7 @@ class LockerTest extends \PHPUnit_Framework_TestCase
|
|||
$repo = $this->createRepositoryManagerMock();
|
||||
$inst = $this->createInstallationManagerMock();
|
||||
|
||||
$locker = new Locker(new NullIO, $json, $repo, $inst, 'md5');
|
||||
$locker = new Locker(new NullIO, $json, $repo, $inst, 'md5', 'contentMd5');
|
||||
|
||||
$json
|
||||
->expects($this->once())
|
||||
|
@ -193,6 +194,38 @@ class LockerTest extends \PHPUnit_Framework_TestCase
|
|||
$this->assertFalse($locker->isFresh());
|
||||
}
|
||||
|
||||
public function testIsFreshWithContentHash()
|
||||
{
|
||||
$json = $this->createJsonFileMock();
|
||||
$repo = $this->createRepositoryManagerMock();
|
||||
$inst = $this->createInstallationManagerMock();
|
||||
|
||||
$locker = new Locker(new NullIO, $json, $repo, $inst, 'md5', 'contentMd5');
|
||||
|
||||
$json
|
||||
->expects($this->once())
|
||||
->method('read')
|
||||
->will($this->returnValue(array('hash' => 'oldMd5', 'content-hash' => 'contentMd5')));
|
||||
|
||||
$this->assertTrue($locker->isFresh());
|
||||
}
|
||||
|
||||
public function testIsFreshFalseWithContentHash()
|
||||
{
|
||||
$json = $this->createJsonFileMock();
|
||||
$repo = $this->createRepositoryManagerMock();
|
||||
$inst = $this->createInstallationManagerMock();
|
||||
|
||||
$locker = new Locker(new NullIO, $json, $repo, $inst, 'md5', 'contentMd5');
|
||||
|
||||
$json
|
||||
->expects($this->once())
|
||||
->method('read')
|
||||
->will($this->returnValue(array('hash' => 'md5', 'content-hash' => 'oldMd5')));
|
||||
|
||||
$this->assertFalse($locker->isFresh());
|
||||
}
|
||||
|
||||
private function createJsonFileMock()
|
||||
{
|
||||
return $this->getMockBuilder('Composer\Json\JsonFile')
|
||||
|
|
Loading…
Reference in New Issue