From 313ea639698dddcbd482e2b20bb36710c5616e55 Mon Sep 17 00:00:00 2001 From: skjnldsv Date: Wed, 13 May 2026 15:57:26 +0200 Subject: [PATCH 1/3] fix: allow file:// URLs with --url option curl returns HTTP code 0 for file:// (no HTTP involved), causing the download step to incorrectly treat a successful local file copy as a failure. Skip the HTTP code check when the URL uses the file:// scheme. Add Behat scenarios covering the happy path (--no-verify) and the missing-signature error for local file URLs. Co-Authored-By: Claude Sonnet 4.6 Signed-off-by: skjnldsv --- index.php | 3 +- lib/Updater.php | 3 +- tests/features/bootstrap/FeatureContext.php | 78 +++++++++++++++++++++ tests/features/cli.feature | 18 +++++ 4 files changed, 100 insertions(+), 2 deletions(-) diff --git a/index.php b/index.php index c95d25f6..324243db 100644 --- a/index.php +++ b/index.php @@ -784,7 +784,8 @@ private function downloadArchive(string $fromUrl, string $toLocation): bool { } $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); - if ($httpCode !== 200 && $httpCode !== 206) { + $isFileUrl = str_starts_with($fromUrl, 'file://'); + if (!$isFileUrl && $httpCode !== 200 && $httpCode !== 206) { fclose($fp); unlink($toLocation); $this->silentLog('[warn] fail to download archive from ' . $fromUrl . '. Error: ' . $httpCode . ' ' . curl_error($ch)); diff --git a/lib/Updater.php b/lib/Updater.php index aeded0ef..949c02d6 100644 --- a/lib/Updater.php +++ b/lib/Updater.php @@ -768,7 +768,8 @@ private function downloadArchive(string $fromUrl, string $toLocation): bool { } $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); - if ($httpCode !== 200 && $httpCode !== 206) { + $isFileUrl = str_starts_with($fromUrl, 'file://'); + if (!$isFileUrl && $httpCode !== 200 && $httpCode !== 206) { fclose($fp); unlink($toLocation); $this->silentLog('[warn] fail to download archive from ' . $fromUrl . '. Error: ' . $httpCode . ' ' . curl_error($ch)); diff --git a/tests/features/bootstrap/FeatureContext.php b/tests/features/bootstrap/FeatureContext.php index 86878d47..fc0428a8 100644 --- a/tests/features/bootstrap/FeatureContext.php +++ b/tests/features/bootstrap/FeatureContext.php @@ -212,6 +212,84 @@ public function theCliUpdaterIsRun() { $this->CLIReturnCode = $returnCode; } + /** + * @Given the archive for version :version is available locally + */ + public function theArchiveForVersionIsAvailableLocally(string $version): void { + if ($this->skipIt) { + return; + } + + $filename = 'nextcloud-' . $version . '.zip'; + if (!file_exists($this->tmpDownloadDir . $filename)) { + $fp = fopen($this->tmpDownloadDir . $filename, 'w+'); + $url = $this->downloadURL . $filename; + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_FILE, $fp); + curl_setopt($ch, CURLOPT_USERAGENT, 'Nextcloud Updater'); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); + if (curl_exec($ch) === false) { + throw new \Exception('Curl error: ' . curl_error($ch)); + } + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + if ($httpCode !== 200) { + throw new \Exception('Download failed for ' . $url . ' - HTTP code: ' . $httpCode); + } + curl_close($ch); + fclose($fp); + } + } + + /** + * @When the CLI updater is run with local file URL for version :version and --no-verify successfully + */ + public function theCliUpdaterIsRunWithLocalFileUrlAndNoVerifySuccessfully(string $version): void { + if ($this->skipIt) { + return; + } + + $this->runUpdaterWithLocalFileUrl($version, noVerify: true); + + if ($this->CLIReturnCode !== 0) { + throw new Exception('updater failed' . PHP_EOL . implode(PHP_EOL, $this->CLIOutput)); + } + } + + /** + * @When the CLI updater is run with local file URL for version :version + */ + public function theCliUpdaterIsRunWithLocalFileUrl(string $version): void { + if ($this->skipIt) { + return; + } + + $this->runUpdaterWithLocalFileUrl($version, noVerify: false); + } + + private function runUpdaterWithLocalFileUrl(string $version, bool $noVerify): void { + $filename = 'nextcloud-' . $version . '.zip'; + $fileUrl = 'file://' . $this->tmpDownloadDir . $filename; + + if (!file_exists($this->buildDir . 'updater.phar')) { + throw new Exception('updater.phar not available - please build it in advance via "box build -c box.json"'); + } + + copy($this->buildDir . 'updater.phar', $this->serverDir . 'nextcloud/updater/updater'); + chdir($this->serverDir . 'nextcloud/updater'); + chmod($this->serverDir . 'nextcloud/updater/updater', 0755); + + $args = '-n --url ' . escapeshellarg($fileUrl); + if ($noVerify) { + $args .= ' --no-verify'; + } + exec('./updater ' . $args . ' 2>&1', $output, $returnCode); + + // sleep to let the opcache do it's work and invalidate the status.php + sleep(5); + $this->CLIOutput = $output; + $this->CLIReturnCode = $returnCode; + } + /** * @param $version */ diff --git a/tests/features/cli.feature b/tests/features/cli.feature index 9cd1db17..6480bc3a 100644 --- a/tests/features/cli.feature +++ b/tests/features/cli.feature @@ -114,3 +114,21 @@ Feature: CLI updater And the installed version should be 26.0.0 And maintenance mode should be off And upgrade is not required + + Scenario: Update via local file URL with --no-verify - 26.0.0 to 26.0.13 + Given the current installed version is 26.0.0 + And the archive for version 26.0.13 is available locally + When the CLI updater is run with local file URL for version 26.0.13 and --no-verify successfully + Then the installed version should be 26.0.1 + And maintenance mode should be off + And upgrade is not required + + Scenario: Update via local file URL without --no-verify fails - 26.0.0 to 26.0.13 + Given the current installed version is 26.0.0 + And the archive for version 26.0.13 is available locally + When the CLI updater is run with local file URL for version 26.0.13 + Then the return code should not be 0 + And the output should contain "You need to provide a signature with --signature or skip integrity check with --no-verify." + And the installed version should be 26.0.0 + And maintenance mode should be off + And upgrade is not required From 459b48ed7ac3e040e4b3dc47af29b1b7a8a0a768 Mon Sep 17 00:00:00 2001 From: skjnldsv Date: Wed, 13 May 2026 16:42:25 +0200 Subject: [PATCH 2/3] fix: use parse_url() to detect file:// scheme Co-Authored-By: Claude Sonnet 4.6 Signed-off-by: skjnldsv --- lib/Updater.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Updater.php b/lib/Updater.php index 949c02d6..b4bd947b 100644 --- a/lib/Updater.php +++ b/lib/Updater.php @@ -768,7 +768,7 @@ private function downloadArchive(string $fromUrl, string $toLocation): bool { } $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); - $isFileUrl = str_starts_with($fromUrl, 'file://'); + $isFileUrl = parse_url($fromUrl, PHP_URL_SCHEME) === 'file'; if (!$isFileUrl && $httpCode !== 200 && $httpCode !== 206) { fclose($fp); unlink($toLocation); From 469a801bb1e5d5f4d002a8167c1bdfb110387a32 Mon Sep 17 00:00:00 2001 From: skjnldsv Date: Wed, 13 May 2026 16:43:22 +0200 Subject: [PATCH 3/3] build(phar): regenerate updater & vendor Signed-off-by: skjnldsv --- index.php | 2 +- updater.phar | Bin 1325355 -> 1325433 bytes .../.github/workflows/phpstan.yml | 35 -------- .../.github/workflows/tests.yaml | 80 ------------------ .../composer-bin-plugin/.makefile/touch.sh | 61 ------------- .../composer-bin-plugin/.phive/phars.xml | 6 -- .../bamarni/composer-bin-plugin/composer.json | 12 +-- .../src/BamarniBinPlugin.php | 1 + .../src/Command/BinCommand.php | 3 + .../Command/CouldNotCreateNamespaceDir.php | 1 + .../composer-bin-plugin/src/Config/Config.php | 1 + .../src/Input/BinInputFactory.php | 8 +- .../src/Input/InvalidBinInput.php | 1 + vendor/composer/installed.json | 22 ++--- vendor/composer/installed.php | 10 +-- 15 files changed, 35 insertions(+), 208 deletions(-) delete mode 100644 vendor/bamarni/composer-bin-plugin/.github/workflows/phpstan.yml delete mode 100644 vendor/bamarni/composer-bin-plugin/.github/workflows/tests.yaml delete mode 100755 vendor/bamarni/composer-bin-plugin/.makefile/touch.sh delete mode 100644 vendor/bamarni/composer-bin-plugin/.phive/phars.xml diff --git a/index.php b/index.php index 324243db..ccba6572 100644 --- a/index.php +++ b/index.php @@ -784,7 +784,7 @@ private function downloadArchive(string $fromUrl, string $toLocation): bool { } $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); - $isFileUrl = str_starts_with($fromUrl, 'file://'); + $isFileUrl = parse_url($fromUrl, PHP_URL_SCHEME) === 'file'; if (!$isFileUrl && $httpCode !== 200 && $httpCode !== 206) { fclose($fp); unlink($toLocation); diff --git a/updater.phar b/updater.phar index 11bd0f4bf13b02dae6250f80ced18ba2721590a7..ed220978ada8dd8ad6aecbeb27ec630e9238c338 100755 GIT binary patch delta 8432 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 diff --git a/vendor/bamarni/composer-bin-plugin/.github/workflows/phpstan.yml b/vendor/bamarni/composer-bin-plugin/.github/workflows/phpstan.yml deleted file mode 100644 index ebb57672..00000000 --- a/vendor/bamarni/composer-bin-plugin/.github/workflows/phpstan.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: "Static analysis" - -on: - push: - branches: - - "main" - - "master" - pull_request: null - -jobs: - static-analysis: - runs-on: "ubuntu-latest" - name: "PHPStan on PHP ${{ matrix.php }}" - strategy: - fail-fast: false - matrix: - php: - - "8.1" - steps: - - name: "Check out repository code" - uses: "actions/checkout@v2" - - - name: "Setup PHP" - uses: "shivammathur/setup-php@v2" - with: - php-version: "${{ matrix.php }}" - tools: "composer" - - - name: "Install Composer dependencies" - uses: "ramsey/composer-install@v2" - with: - dependency-versions: "highest" - - - name: "Perform static analysis" - run: "make phpstan" diff --git a/vendor/bamarni/composer-bin-plugin/.github/workflows/tests.yaml b/vendor/bamarni/composer-bin-plugin/.github/workflows/tests.yaml deleted file mode 100644 index 5bec38a4..00000000 --- a/vendor/bamarni/composer-bin-plugin/.github/workflows/tests.yaml +++ /dev/null @@ -1,80 +0,0 @@ -name: "Tests" - -on: - push: - branches: - - "main" - - "master" - pull_request: null - -jobs: - unit-tests: - runs-on: "ubuntu-latest" - name: "Unit Tests on PHP ${{ matrix.php }} and ${{ matrix.tools }}" - strategy: - fail-fast: false - matrix: - php: - - "7.2" - - "7.3" - - "7.4" - - "8.0" - - "8.1" - tools: [ "composer" ] - dependency-versions: [ "highest" ] - include: - - php: "7.2" - tools: "composer:v2.0" - dependency-versions: "lowest" - - steps: - - name: "Check out repository code" - uses: "actions/checkout@v2" - - - name: "Setup PHP" - uses: "shivammathur/setup-php@v2" - with: - php-version: "${{ matrix.php }}" - tools: "${{ matrix.tools }}" - - - name: "Install Composer dependencies" - uses: "ramsey/composer-install@v2" - with: - dependency-versions: "${{ matrix.dependency-versions }}" - - - name: "Validate composer.json" - run: "composer validate --strict --no-check-lock" - - - name: "Run tests" - run: "vendor/bin/phpunit --group default" - - e2e-tests: - runs-on: "ubuntu-latest" - name: "E2E Tests on PHP ${{ matrix.php }}" - strategy: - fail-fast: false - matrix: - php: - - "8.1" - - steps: - - name: "Check out repository code" - uses: "actions/checkout@v2" - - - name: "Setup PHP" - uses: "shivammathur/setup-php@v2" - with: - php-version: "${{ matrix.php }}" - tools: "composer" - - - name: "Correct bin plugin version for e2e scenarios (PR-only)" - if: github.event_name == 'pull_request' - run: find e2e -maxdepth 1 -mindepth 1 -type d -exec bash -c "cd {} && composer require --dev bamarni/composer-bin-plugin:dev-${GITHUB_SHA} --no-update" \; - - - name: "Install Composer dependencies" - uses: "ramsey/composer-install@v2" - with: - dependency-versions: "highest" - - - name: "Run tests" - run: "vendor/bin/phpunit --group e2e" diff --git a/vendor/bamarni/composer-bin-plugin/.makefile/touch.sh b/vendor/bamarni/composer-bin-plugin/.makefile/touch.sh deleted file mode 100755 index 5c0a7759..00000000 --- a/vendor/bamarni/composer-bin-plugin/.makefile/touch.sh +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env bash -# -# Takes a given string, e.g. 'bin/console' or 'docker-compose exec php bin/console' -# and split it by words. For each words, if the target is a file, it is touched. -# -# This allows to implement a similar rule to: -# -# ```Makefile -# bin/php-cs-fixer: vendor -# touch $@ -# ``` -# -# Indeed when the rule `bin/php-cs-fixer` is replaced with a docker-compose -# equivalent, it will not play out as nicely. -# -# Arguments: -# $1 - {string} Command potentially containing a file -# - -set -Eeuo pipefail; - - -readonly ERROR_COLOR="\e[41m"; -readonly NO_COLOR="\e[0m"; - - -if [ $# -ne 1 ]; then - printf "${ERROR_COLOR}Illegal number of parameters.${NO_COLOR}\n"; - - exit 1; -fi - - -readonly FILES="$1"; - - -####################################### -# Touch the given file path if the target is a file and do not create the file -# if does not exist. -# -# Globals: -# None -# -# Arguments: -# $1 - {string} File path -# -# Returns: -# None -####################################### -touch_file() { - local file="$1"; - - if [ -e ${file} ]; then - touch -c ${file}; - fi -} - -for file in ${FILES} -do - touch_file ${file}; -done diff --git a/vendor/bamarni/composer-bin-plugin/.phive/phars.xml b/vendor/bamarni/composer-bin-plugin/.phive/phars.xml deleted file mode 100644 index 335086e3..00000000 --- a/vendor/bamarni/composer-bin-plugin/.phive/phars.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/vendor/bamarni/composer-bin-plugin/composer.json b/vendor/bamarni/composer-bin-plugin/composer.json index 5b3809ba..4b76ff1b 100644 --- a/vendor/bamarni/composer-bin-plugin/composer.json +++ b/vendor/bamarni/composer-bin-plugin/composer.json @@ -17,11 +17,11 @@ }, "require-dev": { "ext-json": "*", - "composer/composer": "^2.0", + "composer/composer": "^2.2.26", "phpstan/extension-installer": "^1.1", - "phpstan/phpstan": "^1.8", - "phpstan/phpstan-phpunit": "^1.1", - "phpunit/phpunit": "^8.5 || ^9.5", + "phpstan/phpstan": "^1.8 || ^2.0", + "phpstan/phpstan-phpunit": "^1.1 || ^2.0", + "phpunit/phpunit": "^8.5 || ^9.6 || ^10.0", "symfony/console": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0", "symfony/finder": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0", "symfony/process": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0" @@ -38,9 +38,9 @@ }, "config": { "allow-plugins": { - "phpstan/extension-installer": true, "ergebnis/composer-normalize": true, - "infection/extension-installer": true + "infection/extension-installer": true, + "phpstan/extension-installer": true }, "sort-packages": true }, diff --git a/vendor/bamarni/composer-bin-plugin/src/BamarniBinPlugin.php b/vendor/bamarni/composer-bin-plugin/src/BamarniBinPlugin.php index 1d21c93b..19e36e0a 100644 --- a/vendor/bamarni/composer-bin-plugin/src/BamarniBinPlugin.php +++ b/vendor/bamarni/composer-bin-plugin/src/BamarniBinPlugin.php @@ -24,6 +24,7 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Throwable; + use function count; use function in_array; use function sprintf; diff --git a/vendor/bamarni/composer-bin-plugin/src/Command/BinCommand.php b/vendor/bamarni/composer-bin-plugin/src/Command/BinCommand.php index 9edb4c3e..69c4aa99 100644 --- a/vendor/bamarni/composer-bin-plugin/src/Command/BinCommand.php +++ b/vendor/bamarni/composer-bin-plugin/src/Command/BinCommand.php @@ -19,6 +19,7 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Throwable; + use function chdir; use function count; use function file_exists; @@ -30,6 +31,7 @@ use function mkdir; use function putenv; use function sprintf; + use const GLOB_ONLYDIR; /** @@ -96,6 +98,7 @@ public function isProxyCommand(): bool public function execute(InputInterface $input, OutputInterface $output): int { // Switch to requireComposer() once Composer 2.3 is set as the minimum + // @phpstan-ignore function.alreadyNarrowedType $composer = method_exists($this, 'requireComposer') ? $this->requireComposer() : $this->getComposer(); diff --git a/vendor/bamarni/composer-bin-plugin/src/Command/CouldNotCreateNamespaceDir.php b/vendor/bamarni/composer-bin-plugin/src/Command/CouldNotCreateNamespaceDir.php index 33145078..8985a7cd 100644 --- a/vendor/bamarni/composer-bin-plugin/src/Command/CouldNotCreateNamespaceDir.php +++ b/vendor/bamarni/composer-bin-plugin/src/Command/CouldNotCreateNamespaceDir.php @@ -5,6 +5,7 @@ namespace Bamarni\Composer\Bin\Command; use RuntimeException; + use function sprintf; final class CouldNotCreateNamespaceDir extends RuntimeException diff --git a/vendor/bamarni/composer-bin-plugin/src/Config/Config.php b/vendor/bamarni/composer-bin-plugin/src/Config/Config.php index fa62b3a1..629ab868 100644 --- a/vendor/bamarni/composer-bin-plugin/src/Config/Config.php +++ b/vendor/bamarni/composer-bin-plugin/src/Config/Config.php @@ -5,6 +5,7 @@ namespace Bamarni\Composer\Bin\Config; use Composer\Composer; + use function array_key_exists; use function array_merge; use function function_exists; diff --git a/vendor/bamarni/composer-bin-plugin/src/Input/BinInputFactory.php b/vendor/bamarni/composer-bin-plugin/src/Input/BinInputFactory.php index dab96f68..105afae9 100644 --- a/vendor/bamarni/composer-bin-plugin/src/Input/BinInputFactory.php +++ b/vendor/bamarni/composer-bin-plugin/src/Input/BinInputFactory.php @@ -6,6 +6,7 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\StringInput; + use function array_filter; use function array_map; use function implode; @@ -61,7 +62,7 @@ public static function createInput( public static function createNamespaceInput(InputInterface $previousInput): InputInterface { $matchResult = preg_match( - '/^(.+?\s?)(--(?: .+)?)?$/', + '/^([^\s]+)(.*?\s?)(--(?: .+)?)?$/', $previousInput->__toString(), $matches ); @@ -74,9 +75,10 @@ public static function createNamespaceInput(InputInterface $previousInput): Inpu array_map( 'trim', [ - $matches[1], '--working-dir=.', - $matches[2] ?? '', + $matches[1], + $matches[2], + $matches[3] ?? '', ] ) ); diff --git a/vendor/bamarni/composer-bin-plugin/src/Input/InvalidBinInput.php b/vendor/bamarni/composer-bin-plugin/src/Input/InvalidBinInput.php index 2418d9c8..7f44ff5e 100644 --- a/vendor/bamarni/composer-bin-plugin/src/Input/InvalidBinInput.php +++ b/vendor/bamarni/composer-bin-plugin/src/Input/InvalidBinInput.php @@ -6,6 +6,7 @@ use RuntimeException; use Symfony\Component\Console\Input\InputInterface; + use function sprintf; final class InvalidBinInput extends RuntimeException diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index 55853f22..d44e57cc 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -2,17 +2,17 @@ "packages": [ { "name": "bamarni/composer-bin-plugin", - "version": "1.8.2", - "version_normalized": "1.8.2.0", + "version": "1.9.1", + "version_normalized": "1.9.1.0", "source": { "type": "git", "url": "https://github.com/bamarni/composer-bin-plugin.git", - "reference": "92fd7b1e6e9cdae19b0d57369d8ad31a37b6a880" + "reference": "641d0663f5ac270b1aeec4337b7856f76204df47" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/bamarni/composer-bin-plugin/zipball/92fd7b1e6e9cdae19b0d57369d8ad31a37b6a880", - "reference": "92fd7b1e6e9cdae19b0d57369d8ad31a37b6a880", + "url": "https://api.github.com/repos/bamarni/composer-bin-plugin/zipball/641d0663f5ac270b1aeec4337b7856f76204df47", + "reference": "641d0663f5ac270b1aeec4337b7856f76204df47", "shasum": "" }, "require": { @@ -20,17 +20,17 @@ "php": "^7.2.5 || ^8.0" }, "require-dev": { - "composer/composer": "^2.0", + "composer/composer": "^2.2.26", "ext-json": "*", "phpstan/extension-installer": "^1.1", - "phpstan/phpstan": "^1.8", - "phpstan/phpstan-phpunit": "^1.1", - "phpunit/phpunit": "^8.5 || ^9.5", + "phpstan/phpstan": "^1.8 || ^2.0", + "phpstan/phpstan-phpunit": "^1.1 || ^2.0", + "phpunit/phpunit": "^8.5 || ^9.6 || ^10.0", "symfony/console": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0", "symfony/finder": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0", "symfony/process": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0" }, - "time": "2022-10-31T08:38:03+00:00", + "time": "2026-02-04T10:18:12+00:00", "type": "composer-plugin", "extra": { "class": "Bamarni\\Composer\\Bin\\BamarniBinPlugin" @@ -56,7 +56,7 @@ ], "support": { "issues": "https://github.com/bamarni/composer-bin-plugin/issues", - "source": "https://github.com/bamarni/composer-bin-plugin/tree/1.8.2" + "source": "https://github.com/bamarni/composer-bin-plugin/tree/1.9.1" }, "install-path": "../bamarni/composer-bin-plugin" }, diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php index a121f657..5bfe9212 100644 --- a/vendor/composer/installed.php +++ b/vendor/composer/installed.php @@ -3,7 +3,7 @@ 'name' => '__root__', 'pretty_version' => 'dev-master', 'version' => 'dev-master', - 'reference' => '0deb35c1f4fd23fea55c03db40f07c72603adc43', + 'reference' => 'ef7c1a2fde3c86416f5ca4805dd9f0cbf30e4385', 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), @@ -13,16 +13,16 @@ '__root__' => array( 'pretty_version' => 'dev-master', 'version' => 'dev-master', - 'reference' => '0deb35c1f4fd23fea55c03db40f07c72603adc43', + 'reference' => 'ef7c1a2fde3c86416f5ca4805dd9f0cbf30e4385', 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), 'dev_requirement' => false, ), 'bamarni/composer-bin-plugin' => array( - 'pretty_version' => '1.8.2', - 'version' => '1.8.2.0', - 'reference' => '92fd7b1e6e9cdae19b0d57369d8ad31a37b6a880', + 'pretty_version' => '1.9.1', + 'version' => '1.9.1.0', + 'reference' => '641d0663f5ac270b1aeec4337b7856f76204df47', 'type' => 'composer-plugin', 'install_path' => __DIR__ . '/../bamarni/composer-bin-plugin', 'aliases' => array(),