diff --git a/bin/pie b/bin/pie
index 947208fa..dbf10420 100755
--- a/bin/pie
+++ b/bin/pie
@@ -14,6 +14,7 @@ use Php\Pie\Command\RepositoryAddCommand;
use Php\Pie\Command\RepositoryListCommand;
use Php\Pie\Command\RepositoryRemoveCommand;
use Php\Pie\Command\SelfUpdateCommand;
+use Php\Pie\Command\SelfVerifyCommand;
use Php\Pie\Command\ShowCommand;
use Php\Pie\Command\UninstallCommand;
use Php\Pie\Util\PieVersion;
@@ -45,6 +46,7 @@ $application->setCommandLoader(new ContainerCommandLoader(
'repository:remove' => RepositoryRemoveCommand::class,
'uninstall' => UninstallCommand::class,
'self-update' => SelfUpdateCommand::class,
+ 'self-verify' => SelfVerifyCommand::class,
'install-extensions-for-project' => InstallExtensionsForProjectCommand::class,
]
));
diff --git a/src/Command/SelfUpdateCommand.php b/src/Command/SelfUpdateCommand.php
index 4faf1e50..8f55101b 100644
--- a/src/Command/SelfUpdateCommand.php
+++ b/src/Command/SelfUpdateCommand.php
@@ -10,6 +10,7 @@
use Php\Pie\ComposerIntegration\PieComposerFactory;
use Php\Pie\ComposerIntegration\PieComposerRequest;
use Php\Pie\ComposerIntegration\QuieterConsoleIO;
+use Php\Pie\File\FullPathToSelf;
use Php\Pie\File\SudoFilePut;
use Php\Pie\SelfManage\Update\FetchPieReleaseFromGitHub;
use Php\Pie\SelfManage\Update\ReleaseMetadata;
@@ -24,14 +25,10 @@
use Symfony\Component\Console\Output\OutputInterface;
use function file_get_contents;
-use function getcwd;
use function preg_match;
-use function realpath;
use function sprintf;
use function unlink;
-use const DIRECTORY_SEPARATOR;
-
#[AsCommand(
name: 'self-update',
description: 'Self update PIE',
@@ -67,7 +64,7 @@ public function execute(InputInterface $input, OutputInterface $output): int
if (! PieVersion::isPharBuild()) {
$output->writeln('Aborting! You are not running a PHAR, cannot self-update.');
- return 1;
+ return Command::FAILURE;
}
$targetPlatform = CommandHelper::determineTargetPlatformFromInputs($input, $output);
@@ -141,8 +138,7 @@ public function execute(InputInterface $input, OutputInterface $output): int
return Command::FAILURE;
}
- $phpSelf = $_SERVER['PHP_SELF'] ?? '';
- $fullPathToSelf = $this->isAbsolutePath($phpSelf) ? $phpSelf : (getcwd() . DIRECTORY_SEPARATOR . $phpSelf);
+ $fullPathToSelf = (new FullPathToSelf())();
$output->writeln(
sprintf('Writing new version to %s', $fullPathToSelf),
OutputInterface::VERBOSITY_VERBOSE,
@@ -153,21 +149,4 @@ public function execute(InputInterface $input, OutputInterface $output): int
return Command::SUCCESS;
}
-
- private function isAbsolutePath(string $path): bool
- {
- if (realpath($path) === $path) {
- return true;
- }
-
- if ($path === '' || $path === '.') {
- return false;
- }
-
- if (preg_match('#^[a-zA-Z]:\\\\#', $path)) {
- return true;
- }
-
- return $path[0] === '/' || $path[0] === '\\';
- }
}
diff --git a/src/Command/SelfVerifyCommand.php b/src/Command/SelfVerifyCommand.php
new file mode 100644
index 00000000..b012c3e0
--- /dev/null
+++ b/src/Command/SelfVerifyCommand.php
@@ -0,0 +1,89 @@
+writeln('Aborting! You are not running a PHAR, cannot self-update.');
+
+ return Command::FAILURE;
+ }
+
+ $targetPlatform = CommandHelper::determineTargetPlatformFromInputs($input, $output);
+ $composer = PieComposerFactory::createPieComposer(
+ $this->container,
+ PieComposerRequest::noOperation(
+ $output,
+ $targetPlatform,
+ ),
+ );
+ $httpDownloader = new HttpDownloader($this->io, $composer->getConfig());
+ $authHelper = new AuthHelper($this->io, $composer->getConfig());
+ $latestRelease = new ReleaseMetadata(PieVersion::get(), 'blah');
+ $pharFilename = BinaryFile::fromFileWithSha256Checksum((new FullPathToSelf())());
+ $verifyPiePhar = VerifyPieReleaseUsingAttestation::factory($this->githubApiBaseUrl, $httpDownloader, $authHelper);
+
+ try {
+ $verifyPiePhar->verify($latestRelease, $pharFilename, $output);
+ } catch (FailedToVerifyRelease $failedToVerifyRelease) {
+ $output->writeln(sprintf(
+ '❌ Failed to verify the pie.phar release %s: %s',
+ $latestRelease->tag,
+ $failedToVerifyRelease->getMessage(),
+ ));
+
+ return Command::FAILURE;
+ }
+
+ $output->writeln(sprintf(
+ '✅ You are running an authentic PIE version %s.',
+ $latestRelease->tag,
+ ));
+
+ return Command::SUCCESS;
+ }
+}
diff --git a/src/Container.php b/src/Container.php
index 1e5c82c3..02233a06 100644
--- a/src/Container.php
+++ b/src/Container.php
@@ -18,6 +18,7 @@
use Php\Pie\Command\RepositoryListCommand;
use Php\Pie\Command\RepositoryRemoveCommand;
use Php\Pie\Command\SelfUpdateCommand;
+use Php\Pie\Command\SelfVerifyCommand;
use Php\Pie\Command\ShowCommand;
use Php\Pie\Command\UninstallCommand;
use Php\Pie\ComposerIntegration\MinimalHelperSet;
@@ -84,6 +85,7 @@ static function (ConsoleCommandEvent $event) use (&$displayedBanner): void {
$container->singleton(RepositoryRemoveCommand::class);
$container->singleton(UninstallCommand::class);
$container->singleton(SelfUpdateCommand::class);
+ $container->singleton(SelfVerifyCommand::class);
$container->singleton(InstallExtensionsForProjectCommand::class);
$container->singleton(QuieterConsoleIO::class, static function (ContainerInterface $container): QuieterConsoleIO {
@@ -109,6 +111,10 @@ static function (ConsoleCommandEvent $event) use (&$displayedBanner): void {
->needs('$githubApiBaseUrl')
->give('https://api.github.com');
+ $container->when(SelfVerifyCommand::class)
+ ->needs('$githubApiBaseUrl')
+ ->give('https://api.github.com');
+
$container->singleton(
Build::class,
static function (ContainerInterface $container): Build {
diff --git a/src/File/FullPathToSelf.php b/src/File/FullPathToSelf.php
new file mode 100644
index 00000000..8f559120
--- /dev/null
+++ b/src/File/FullPathToSelf.php
@@ -0,0 +1,50 @@
+isAbsolutePath($phpSelf)
+ ? $phpSelf
+ : (getcwd() . DIRECTORY_SEPARATOR . $phpSelf);
+ }
+
+ private function isAbsolutePath(string $path): bool
+ {
+ if (realpath($path) === $path) {
+ return true;
+ }
+
+ if ($path === '' || $path === '.') {
+ return false;
+ }
+
+ if (preg_match('#^[a-zA-Z]:\\\\#', $path)) {
+ return true;
+ }
+
+ return $path[0] === '/' || $path[0] === '\\';
+ }
+}
diff --git a/src/Installing/InstallForPhpProject/InstallSelectedPackage.php b/src/Installing/InstallForPhpProject/InstallSelectedPackage.php
index 8d316b35..3245f754 100644
--- a/src/Installing/InstallForPhpProject/InstallSelectedPackage.php
+++ b/src/Installing/InstallForPhpProject/InstallSelectedPackage.php
@@ -5,18 +5,16 @@
namespace Php\Pie\Installing\InstallForPhpProject;
use Php\Pie\Command\CommandHelper;
+use Php\Pie\File\FullPathToSelf;
use Php\Pie\Util\Process;
-use RuntimeException;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use function array_filter;
-use function array_key_exists;
use function array_walk;
use function getcwd;
use function in_array;
-use function is_string;
use const ARRAY_FILTER_USE_BOTH;
@@ -25,14 +23,8 @@ class InstallSelectedPackage
{
public function withPieCli(string $selectedPackage, InputInterface $input, OutputInterface $output): void
{
- /** @psalm-suppress TypeDoesNotContainType */
- $self = array_key_exists('PHP_SELF', $_SERVER) && is_string($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : '';
- if ($self === '') {
- throw new RuntimeException('Could not find PHP_SELF');
- }
-
$process = [
- $self,
+ (new FullPathToSelf())(),
'install',
$selectedPackage,
];
diff --git a/src/Util/PieVersion.php b/src/Util/PieVersion.php
index 56166b9c..ab1585fd 100644
--- a/src/Util/PieVersion.php
+++ b/src/Util/PieVersion.php
@@ -45,6 +45,8 @@ public static function isPharBuild(): bool
* realistic-looking version; usually either a tag (e.g. `2.0.0`), or a tag
* and following commit short hash (e.g. `2.0.0@e558e33`). If not this will
* fall back to some other techniques to try to determine a version.
+ *
+ * @return non-empty-string
*/
public static function get(): string
{
@@ -62,7 +64,7 @@ public static function get(): string
* likely be something like `dev-main` (branch name).
*/
$installedVersion = InstalledVersions::getVersion(InstalledVersions::getRootPackage()['name']);
- if ($installedVersion === null) {
+ if ($installedVersion === null || $installedVersion === '') {
return self::SYMFONY_MAGIC_CONST_UNKNOWN;
}