diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index f4107a0b..6405a8f0 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -192,7 +192,7 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: 8.1 + php-version: 8.5 extensions: intl, sodium, zip env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/composer.json b/composer.json index 26d76241..6db13899 100644 --- a/composer.json +++ b/composer.json @@ -49,7 +49,8 @@ "phpstan/phpstan": "^2.1.46", "phpstan/phpstan-phpunit": "^2.0.16", "phpstan/phpstan-webmozart-assert": "^2.0", - "phpunit/phpunit": "^10.5.63" + "phpunit/phpunit": "^10.5.63", + "thecodingmachine/phpstan-safe-rule": "^1.4" }, "replace": { "symfony/polyfill-php81": "*", diff --git a/composer.lock b/composer.lock index 3d1cd052..ca2ef82e 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "5e03f2773c1c772133c2e0ccea2f207b", + "content-hash": "94204642ed77d8a9db62c6ecb183d8d8", "packages": [ { "name": "composer/ca-bundle", @@ -5641,6 +5641,64 @@ ], "time": "2026-02-06T18:32:11+00:00" }, + { + "name": "thecodingmachine/phpstan-safe-rule", + "version": "v1.4.3", + "source": { + "type": "git", + "url": "https://github.com/thecodingmachine/phpstan-safe-rule.git", + "reference": "5c804889253ce9498ef185e108e9f94b6023208e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thecodingmachine/phpstan-safe-rule/zipball/5c804889253ce9498ef185e108e9f94b6023208e", + "reference": "5c804889253ce9498ef185e108e9f94b6023208e", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^5", + "php": "^8.1", + "phpstan/phpstan": "^2.1.11", + "thecodingmachine/safe": "^1.2 || ^2.0 || ^3.0" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^10.4", + "squizlabs/php_codesniffer": "^3.4" + }, + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "phpstan-safe-rule.neon" + ] + }, + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "TheCodingMachine\\Safe\\PHPStan\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "David Négrier", + "email": "d.negrier@thecodingmachine.com" + } + ], + "description": "A PHPStan rule to detect safety issues. Must be used in conjunction with thecodingmachine/safe", + "support": { + "issues": "https://github.com/thecodingmachine/phpstan-safe-rule/issues", + "source": "https://github.com/thecodingmachine/phpstan-safe-rule/tree/v1.4.3" + }, + "time": "2025-11-21T09:41:49+00:00" + }, { "name": "theseer/tokenizer", "version": "1.3.1", diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index dde554b7..b1113a93 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -18,48 +18,18 @@ parameters: count: 1 path: src/Command/InstallExtensionsForProjectCommand.php - - - message: '#^Parameter \#1 \$directory of function chdir expects string, string\|false given\.$#' - identifier: argument.type - count: 1 - path: src/Command/InstallExtensionsForProjectCommand.php - - - - message: '#^Parameter \#1 \$path of function realpath expects string, string\|false given\.$#' - identifier: argument.type - count: 1 - path: src/Command/InstallExtensionsForProjectCommand.php - - - - message: '#^Strict comparison using \=\=\= between non\-empty\-string and '''' will always evaluate to false\.$#' - identifier: identical.alwaysFalse - count: 1 - path: src/Command/InstallExtensionsForProjectCommand.php - - message: '#^Cannot cast mixed to string\.$#' identifier: cast.string count: 2 path: src/Command/RepositoryAddCommand.php - - - message: '#^Parameter \#1 \$haystack of function str_contains expects string, string\|false given\.$#' - identifier: argument.type - count: 1 - path: src/Command/RepositoryAddCommand.php - - message: '#^Cannot cast mixed to string\.$#' identifier: cast.string count: 1 path: src/Command/RepositoryRemoveCommand.php - - - message: '#^Parameter \#2 \$content of static method Php\\Pie\\File\\SudoFilePut\:\:contents\(\) expects string, string\|false given\.$#' - identifier: argument.type - count: 1 - path: src/Command/SelfUpdateCommand.php - - message: '#^Cannot cast mixed to string\.$#' identifier: cast.string @@ -90,36 +60,6 @@ parameters: count: 1 path: src/ComposerIntegration/PieComposerInstaller.php - - - message: '#^Method Php\\Pie\\ComposerIntegration\\PieJsonEditor\:\:addRepository\(\) should return string but returns string\|false\.$#' - identifier: return.type - count: 1 - path: src/ComposerIntegration/PieJsonEditor.php - - - - message: '#^Method Php\\Pie\\ComposerIntegration\\PieJsonEditor\:\:addRequire\(\) should return string but returns string\|false\.$#' - identifier: return.type - count: 1 - path: src/ComposerIntegration/PieJsonEditor.php - - - - message: '#^Method Php\\Pie\\ComposerIntegration\\PieJsonEditor\:\:excludePackagistOrg\(\) should return string but returns string\|false\.$#' - identifier: return.type - count: 1 - path: src/ComposerIntegration/PieJsonEditor.php - - - - message: '#^Method Php\\Pie\\ComposerIntegration\\PieJsonEditor\:\:removeRepository\(\) should return string but returns string\|false\.$#' - identifier: return.type - count: 1 - path: src/ComposerIntegration/PieJsonEditor.php - - - - message: '#^Method Php\\Pie\\ComposerIntegration\\PieJsonEditor\:\:removeRequire\(\) should return string but returns string\|false\.$#' - identifier: return.type - count: 1 - path: src/ComposerIntegration/PieJsonEditor.php - - message: '#^Call to function assert\(\) with true will always evaluate to true\.$#' identifier: function.alreadyNarrowedType @@ -138,12 +78,6 @@ parameters: count: 1 path: src/ComposerIntegration/VendorCleanup.php - - - message: '#^Parameter \#1 \$implementation of method Illuminate\\Contracts\\Container\\ContextualBindingBuilder\:\:give\(\) expects array\|Closure\|string, non\-empty\-string\|false given\.$#' - identifier: argument.type - count: 1 - path: src/Container.php - - message: '#^Call to static method Php\\Pie\\DependencyResolver\\DetermineMinimumStability\:\:assertValidStabilityString\(\) with ''alpha''\|''beta''\|''dev''\|''RC''\|''stable'' will always evaluate to true\.$#' identifier: staticMethod.alreadyNarrowedType @@ -216,48 +150,18 @@ parameters: count: 1 path: src/ExtensionName.php - - - message: '#^Parameter \#2 \$checksum of class Php\\Pie\\File\\BinaryFile constructor expects non\-empty\-string, non\-falsy\-string\|false given\.$#' - identifier: argument.type - count: 1 - path: src/File/BinaryFile.php - - message: '#^Negated boolean expression is always false\.$#' identifier: booleanNot.alwaysFalse count: 1 path: src/File/SudoUnlink.php - - - message: '#^Right side of \|\| is always true\.$#' - identifier: booleanOr.rightAlwaysTrue - count: 1 - path: src/File/SudoUnlink.php - - - - message: '#^Unreachable statement \- code above always terminates\.$#' - identifier: deadCode.unreachable - count: 1 - path: src/File/SudoUnlink.php - - message: '#^If condition is always true\.$#' identifier: if.alwaysTrue count: 1 path: src/File/WindowsDelete.php - - - message: '#^Argument of an invalid type list\\|false supplied for foreach, only iterables are supported\.$#' - identifier: foreach.nonIterable - count: 1 - path: src/Installing/Ini/IsExtensionAlreadyInTheIniFile.php - - - - message: '#^Parameter \#2 \$array of function array_key_exists expects array, array\|false given\.$#' - identifier: argument.type - count: 2 - path: src/Installing/Ini/IsExtensionAlreadyInTheIniFile.php - - message: '#^Call to function array_key_exists\(\) with ''downloads'' and array\{name\: string, description\: string\|null, abandoned\?\: string\|true, url\?\: string\} will always evaluate to false\.$#' identifier: function.impossibleType @@ -354,12 +258,6 @@ parameters: count: 1 path: test/integration/Installing/WindowsInstallTest.php - - - message: '#^Parameter \#2 \$extractedSourcePath of static method Php\\Pie\\Downloading\\DownloadedPackage\:\:fromPackageAndExtractedPath\(\) expects string, string\|false given\.$#' - identifier: argument.type - count: 2 - path: test/unit/ComposerIntegration/BundledPhpExtensionsRepositoryTest.php - - message: '#^Match expression does not handle remaining value\: string$#' identifier: match.unhandled @@ -372,12 +270,6 @@ parameters: count: 1 path: test/unit/ComposerIntegration/VendorCleanupTest.php - - - message: '#^Parameter \#2 \$extractedSourcePath of static method Php\\Pie\\Downloading\\DownloadedPackage\:\:fromPackageAndExtractedPath\(\) expects string, string\|false given\.$#' - identifier: argument.type - count: 3 - path: test/unit/Downloading/DownloadedPackageTest.php - - message: '#^Parameter \#1 \$phpExt of method Composer\\Package\\Package\:\:setPhpExt\(\) expects array\{extension\-name\?\: string, priority\?\: int, support\-zts\?\: bool, support\-nts\?\: bool, build\-path\?\: string\|null, download\-url\-method\?\: list\\|string, os\-families\?\: non\-empty\-list\, os\-families\-exclude\?\: non\-empty\-list\, \.\.\.\}\|null, array\{extension\-name\: null\} given\.$#' identifier: argument.type @@ -437,69 +329,3 @@ parameters: identifier: property.notFound count: 4 path: test/unit/SelfManage/BuildTools/PhpizeBuildToolFinderTest.php - - - - message: '#^Method Php\\PieUnitTest\\SelfManage\\Verify\\FallbackVerificationUsingOpenSslTest\:\:prepareCertificateAndSignature\(\) should return array\{string, string\} but returns array\{mixed, mixed\}\.$#' - identifier: return.type - count: 1 - path: test/unit/SelfManage/Verify/FallbackVerificationUsingOpenSslTest.php - - - - message: '#^Parameter \#1 \$certificate of function openssl_x509_export expects OpenSSLCertificate\|string, OpenSSLCertificate\|false given\.$#' - identifier: argument.type - count: 2 - path: test/unit/SelfManage/Verify/FallbackVerificationUsingOpenSslTest.php - - - - message: '#^Parameter \#1 \$csr of function openssl_csr_sign expects OpenSSLCertificateSigningRequest\|string, OpenSSLCertificateSigningRequest\|false given\.$#' - identifier: argument.type - count: 2 - path: test/unit/SelfManage/Verify/FallbackVerificationUsingOpenSslTest.php - - - - message: '#^Parameter \#1 \$dsseEnvelopePayload of method Php\\PieUnitTest\\SelfManage\\Verify\\FallbackVerificationUsingOpenSslTest\:\:prepareCertificateAndSignature\(\) expects string, string\|false given\.$#' - identifier: argument.type - count: 3 - path: test/unit/SelfManage/Verify/FallbackVerificationUsingOpenSslTest.php - - - - message: '#^Parameter \#1 \$string of function trim expects string, array\\|string given\.$#' - identifier: argument.type - count: 1 - path: test/unit/SelfManage/Verify/FallbackVerificationUsingOpenSslTest.php - - - - message: '#^Parameter \#2 \$ca_certificate of function openssl_csr_sign expects OpenSSLCertificate\|string\|null, OpenSSLCertificate\|false given\.$#' - identifier: argument.type - count: 1 - path: test/unit/SelfManage/Verify/FallbackVerificationUsingOpenSslTest.php - - - - message: '#^Parameter \#2 \$dsseEnvelopePayload of method Php\\PieUnitTest\\SelfManage\\Verify\\FallbackVerificationUsingOpenSslTest\:\:mockAttestationResponse\(\) expects string, string\|false given\.$#' - identifier: argument.type - count: 3 - path: test/unit/SelfManage/Verify/FallbackVerificationUsingOpenSslTest.php - - - - message: '#^Parameter \#3 \$private_key of function openssl_csr_sign expects array\|OpenSSLAsymmetricKey\|OpenSSLCertificate\|string, mixed given\.$#' - identifier: argument.type - count: 2 - path: test/unit/SelfManage/Verify/FallbackVerificationUsingOpenSslTest.php - - - - message: '#^Parameter \#3 \$private_key of function openssl_sign expects array\|OpenSSLAsymmetricKey\|OpenSSLCertificate\|string, mixed given\.$#' - identifier: argument.type - count: 1 - path: test/unit/SelfManage/Verify/FallbackVerificationUsingOpenSslTest.php - - - - message: '#^Parameter \#3 \$subject of function str_replace expects array\\|string, mixed given\.$#' - identifier: argument.type - count: 1 - path: test/unit/SelfManage/Verify/FallbackVerificationUsingOpenSslTest.php - - - - message: '#^Parameter \#4 \$body of class Composer\\Util\\Http\\Response constructor expects string\|null, string\|false given\.$#' - identifier: argument.type - count: 1 - path: test/unit/SelfManage/Verify/FallbackVerificationUsingOpenSslTest.php diff --git a/phpstan.neon b/phpstan.neon index 80f87e1d..2f7942ad 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -3,6 +3,7 @@ includes: - vendor/bnf/phpstan-psr-container/extension.neon - vendor/phpstan/phpstan-webmozart-assert/extension.neon - vendor/phpstan/phpstan-phpunit/extension.neon + - vendor/thecodingmachine/phpstan-safe-rule/phpstan-safe-rule.neon parameters: level: 10 diff --git a/src/Building/UnixBuild.php b/src/Building/UnixBuild.php index e067a3de..35ebac89 100644 --- a/src/Building/UnixBuild.php +++ b/src/Building/UnixBuild.php @@ -20,7 +20,7 @@ use function count; use function file_exists; use function implode; -use function rename; +use function Safe\rename; use function sprintf; use const DIRECTORY_SEPARATOR; diff --git a/src/Command/InstallExtensionsForProjectCommand.php b/src/Command/InstallExtensionsForProjectCommand.php index 511d43bb..2ae5b02e 100644 --- a/src/Command/InstallExtensionsForProjectCommand.php +++ b/src/Command/InstallExtensionsForProjectCommand.php @@ -24,6 +24,8 @@ use Php\Pie\Platform\InstalledPiePackages; use Php\Pie\Util\Emoji; use Psr\Container\ContainerInterface; +use Safe\Exceptions\DirException; +use Safe\Exceptions\FilesystemException; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; @@ -38,14 +40,13 @@ use function array_merge; use function array_walk; use function assert; -use function chdir; use function count; -use function getcwd; use function implode; use function in_array; use function is_dir; -use function is_string; -use function realpath; +use function Safe\chdir; +use function Safe\getcwd; +use function Safe\realpath; use function sprintf; use function strtolower; @@ -104,9 +105,13 @@ public function execute(InputInterface $input, OutputInterface $output): int $rootPackage = $this->composerFactoryForProject->rootPackage($this->io); if (ExtensionType::isValid($rootPackage->getType())) { - $cwd = realpath(getcwd()); - if (! is_string($cwd) || $cwd === '') { - $this->io->writeError('Failed to determine current working directory.'); + try { + $cwd = realpath(getcwd()); + } catch (FilesystemException | DirException $e) { + $this->io->writeError(sprintf( + 'Failed to determine current working directory: %s', + $e->getMessage(), + )); $restoreWorkingDir(); diff --git a/src/Command/RepositoryAddCommand.php b/src/Command/RepositoryAddCommand.php index 7c0fda66..92463661 100644 --- a/src/Command/RepositoryAddCommand.php +++ b/src/Command/RepositoryAddCommand.php @@ -17,7 +17,7 @@ use Symfony\Component\Console\Output\OutputInterface; use Webmozart\Assert\Assert; -use function realpath; +use function Safe\realpath; use function str_contains; #[AsCommand( diff --git a/src/Command/SelfUpdateCommand.php b/src/Command/SelfUpdateCommand.php index 8e371632..f46fef3f 100644 --- a/src/Command/SelfUpdateCommand.php +++ b/src/Command/SelfUpdateCommand.php @@ -30,9 +30,9 @@ use Symfony\Component\Console\Output\OutputInterface; use Throwable; -use function file_get_contents; +use function Safe\file_get_contents; +use function Safe\unlink; use function sprintf; -use function unlink; #[AsCommand( name: 'self-update', diff --git a/src/ComposerIntegration/BundledPhpExtensionsRepository.php b/src/ComposerIntegration/BundledPhpExtensionsRepository.php index 7c977505..f285b90a 100644 --- a/src/ComposerIntegration/BundledPhpExtensionsRepository.php +++ b/src/ComposerIntegration/BundledPhpExtensionsRepository.php @@ -15,6 +15,7 @@ use Php\Pie\Platform\TargetPlatform; use Php\Pie\Util\Process; use RuntimeException; +use Safe\Exceptions\FilesystemException; use Symfony\Component\Process\Exception\ProcessFailedException; use function array_combine; @@ -24,7 +25,7 @@ use function count; use function implode; use function in_array; -use function realpath; +use function Safe\realpath; use function sprintf; /** @internal This is not public API for PIE, so should not be depended upon unless you accept the risk of BC breaks */ @@ -289,16 +290,18 @@ public static function augmentMakeCommandForPhpBundledExtensions(array $makeComm 'php/dom', ]) ) { - $path = (string) realpath($downloadedPackage->extractedSourcePath . '/../..'); - if ($path !== '') { - $extraCflags[] = '-I' . $path; + try { + $extraCflags[] = '-I' . realpath($downloadedPackage->extractedSourcePath . '/../..'); + } catch (FilesystemException) { + // ignore; the path does not exist } } if ($downloadedPackage->package->name() === 'php/dom') { - $path = (string) realpath($downloadedPackage->extractedSourcePath . '/../../ext/lexbor'); - if ($path !== '') { - $extraCflags[] = '-I' . $path; + try { + $extraCflags[] = '-I' . realpath($downloadedPackage->extractedSourcePath . '/../../ext/lexbor'); + } catch (FilesystemException) { + // ignore; the lexbor path does not exist } } diff --git a/src/ComposerIntegration/PieJsonEditor.php b/src/ComposerIntegration/PieJsonEditor.php index 475bfc47..3a84f71c 100644 --- a/src/ComposerIntegration/PieJsonEditor.php +++ b/src/ComposerIntegration/PieJsonEditor.php @@ -9,12 +9,13 @@ use Php\Pie\Platform; use Php\Pie\Platform\TargetPlatform; use RuntimeException; +use Safe\Exceptions\FilesystemException; use function file_exists; -use function file_get_contents; -use function file_put_contents; -use function mkdir; use function rtrim; +use function Safe\file_get_contents; +use function Safe\file_put_contents; +use function Safe\mkdir; use function sprintf; use function str_replace; @@ -51,12 +52,17 @@ public function ensureExists(): self mkdir($this->pieWorkingDirectory, recursive: true); } - if (file_put_contents($this->pieJsonFilename, "{\n}\n") === false) { - throw new RuntimeException(sprintf( - 'Failed to create pie.json in %s (working directory: %s)', - $this->pieJsonFilename, - $this->pieWorkingDirectory, - )); + try { + file_put_contents($this->pieJsonFilename, "{\n}\n"); + } catch (FilesystemException $previous) { + throw new RuntimeException( + sprintf( + 'Failed to create pie.json in %s (working directory: %s)', + $this->pieJsonFilename, + $this->pieWorkingDirectory, + ), + previous: $previous, + ); } return $this; diff --git a/src/ComposerIntegration/VendorCleanup.php b/src/ComposerIntegration/VendorCleanup.php index 52d63216..967828f0 100644 --- a/src/ComposerIntegration/VendorCleanup.php +++ b/src/ComposerIntegration/VendorCleanup.php @@ -7,12 +7,13 @@ use Composer\Composer; use Composer\IO\IOInterface; use Composer\Util\Filesystem; +use Safe\Exceptions\DirException; +use Webmozart\Assert\Assert; use function array_filter; use function array_walk; use function in_array; -use function is_array; -use function scandir; +use function Safe\scandir; use function sprintf; use const DIRECTORY_SEPARATOR; @@ -28,14 +29,18 @@ public function __construct( public function __invoke(Composer $composer): void { - $vendorDir = (string) $composer->getConfig()->get('vendor-dir'); - $vendorContents = scandir($vendorDir); + $vendorDir = (string) $composer->getConfig()->get('vendor-dir'); - if (! is_array($vendorContents)) { + try { + $vendorContents = scandir($vendorDir); + Assert::isList($vendorContents); + Assert::allString($vendorContents); + } catch (DirException $e) { $this->io->write( sprintf( - 'Vendor directory (vendor-dir config) %s seemed invalid?', + 'Vendor directory (vendor-dir config) %s seemed invalid? %s', $vendorDir, + $e->getMessage(), ), verbosity: IOInterface::VERY_VERBOSE, ); diff --git a/src/Container.php b/src/Container.php index 076e64f8..7dfb663a 100644 --- a/src/Container.php +++ b/src/Container.php @@ -53,7 +53,7 @@ use Symfony\Component\EventDispatcher\EventDispatcher; use function assert; -use function getcwd; +use function Safe\getcwd; use function str_starts_with; /** @internal This is not public API for PIE, so should not be depended upon unless you accept the risk of BC breaks */ diff --git a/src/DependencyResolver/Package.php b/src/DependencyResolver/Package.php index 154c01ec..f37df660 100644 --- a/src/DependencyResolver/Package.php +++ b/src/DependencyResolver/Package.php @@ -11,6 +11,7 @@ use Php\Pie\ExtensionName; use Php\Pie\ExtensionType; use Php\Pie\Platform\OperatingSystemFamily; +use Safe\Exceptions\UrlException; use Webmozart\Assert\Assert; use function array_key_exists; @@ -20,7 +21,8 @@ use function explode; use function implode; use function is_array; -use function parse_url; +use function is_string; +use function Safe\parse_url; use function str_contains; use function str_starts_with; use function strtolower; @@ -121,8 +123,13 @@ public function githubOrgAndRepository(): string return $this->name; } - $parsed = parse_url($this->downloadUrl); - if ($parsed === false || ! array_key_exists('path', $parsed)) { + try { + $parsed = parse_url($this->downloadUrl); + } catch (UrlException) { + return $this->name; + } + + if (! is_array($parsed) || ! array_key_exists('path', $parsed) || ! is_string($parsed['path'])) { return $this->name; } diff --git a/src/DependencyResolver/ResolveDependencyWithComposer.php b/src/DependencyResolver/ResolveDependencyWithComposer.php index d7873aa7..5cd6b73c 100644 --- a/src/DependencyResolver/ResolveDependencyWithComposer.php +++ b/src/DependencyResolver/ResolveDependencyWithComposer.php @@ -15,7 +15,7 @@ use Php\Pie\Platform\ThreadSafetyMode; use function in_array; -use function preg_match; +use function Safe\preg_match; use function sprintf; use function str_ends_with; diff --git a/src/Downloading/DownloadedPackage.php b/src/Downloading/DownloadedPackage.php index d23b20a4..552aaab2 100644 --- a/src/Downloading/DownloadedPackage.php +++ b/src/Downloading/DownloadedPackage.php @@ -6,14 +6,14 @@ use Php\Pie\DependencyResolver\Package; use Php\Pie\Platform\PrePackagedSourceAssetName; +use Safe\Exceptions\FilesystemException; use function array_map; use function array_unique; use function file_exists; use function is_dir; -use function is_string; use function pathinfo; -use function realpath; +use function Safe\realpath; use function str_replace; use const DIRECTORY_SEPARATOR; @@ -71,13 +71,14 @@ private static function overrideSourcePathUsingBuildPath(Package $package, strin return $extractedSourcePath; } - $extractedSourcePathWithBuildPath = realpath( - $extractedSourcePath - . DIRECTORY_SEPARATOR - . str_replace('{version}', $package->version(), $package->buildPath()), - ); - - if (! is_string($extractedSourcePathWithBuildPath)) { + try { + $extractedSourcePathWithBuildPath = realpath( + $extractedSourcePath + . DIRECTORY_SEPARATOR + . str_replace('{version}', $package->version(), $package->buildPath()), + ); + } catch (FilesystemException) { + // Build path does not exist; likely a configuration error return $extractedSourcePath; } diff --git a/src/ExtensionName.php b/src/ExtensionName.php index 860d5fc0..164cbd2b 100644 --- a/src/ExtensionName.php +++ b/src/ExtensionName.php @@ -11,7 +11,7 @@ use function array_key_exists; use function explode; use function is_string; -use function preg_match; +use function Safe\preg_match; use function sprintf; use function str_starts_with; use function strlen; diff --git a/src/File/BinaryFile.php b/src/File/BinaryFile.php index 873e5cc6..5091149e 100644 --- a/src/File/BinaryFile.php +++ b/src/File/BinaryFile.php @@ -8,7 +8,7 @@ use function file_exists; use function hash_equals; -use function hash_file; +use function Safe\hash_file; /** * @internal This is not public API for PIE, so should not be depended upon unless you accept the risk of BC breaks diff --git a/src/File/FailedToCreateFile.php b/src/File/FailedToCreateFile.php index b788456a..71e0a1bf 100644 --- a/src/File/FailedToCreateFile.php +++ b/src/File/FailedToCreateFile.php @@ -4,25 +4,24 @@ namespace Php\Pie\File; -use Php\Pie\Util\CaptureErrors; use RuntimeException; use Symfony\Component\Process\Exception\ProcessFailedException; +use Throwable; -use function array_column; -use function implode; use function sprintf; -/** @phpstan-import-type CapturedErrorList from CaptureErrors */ class FailedToCreateFile extends RuntimeException { - /** @param CapturedErrorList $recorded */ - public static function fromTouchErrors(string $filename, array $recorded): self + public static function fromTouchError(string $filename, Throwable $previous): self { - return new self(sprintf( - "Failed to create file %s.\n\nErrors:\n - %s", - $filename, - implode("\n - ", array_column($recorded, 'message')), - )); + return new self( + sprintf( + 'Failed to create file %s: %s', + $filename, + $previous->getMessage(), + ), + previous: $previous, + ); } public static function fromNoPermissions(string $filename): self diff --git a/src/File/FailedToUnlinkFile.php b/src/File/FailedToUnlinkFile.php index bc9ccf0c..bcf6ab53 100644 --- a/src/File/FailedToUnlinkFile.php +++ b/src/File/FailedToUnlinkFile.php @@ -4,25 +4,24 @@ namespace Php\Pie\File; -use Php\Pie\Util\CaptureErrors; use RuntimeException; use Symfony\Component\Process\Exception\ProcessFailedException; +use Throwable; -use function array_column; -use function implode; use function sprintf; -/** @phpstan-import-type CapturedErrorList from CaptureErrors */ class FailedToUnlinkFile extends RuntimeException { - /** @param CapturedErrorList $recorded */ - public static function fromUnlinkErrors(string $filename, array $recorded): self + public static function fromUnlinkError(string $filename, Throwable $previous): self { - return new self(sprintf( - "Failed to unlink file %s.\n\nErrors:\n - %s", - $filename, - implode("\n - ", array_column($recorded, 'message')), - )); + return new self( + sprintf( + 'Failed to unlink file %s: %s', + $filename, + $previous->getMessage(), + ), + previous: $previous, + ); } public static function fromNoPermissions(string $filename): self diff --git a/src/File/FailedToWriteFile.php b/src/File/FailedToWriteFile.php index 78d5e1aa..e5e44cf6 100644 --- a/src/File/FailedToWriteFile.php +++ b/src/File/FailedToWriteFile.php @@ -4,31 +4,33 @@ namespace Php\Pie\File; -use Php\Pie\Util\CaptureErrors; use RuntimeException; +use Throwable; -use function array_column; -use function implode; use function sprintf; -/** @phpstan-import-type CapturedErrorList from CaptureErrors */ class FailedToWriteFile extends RuntimeException { - /** @param CapturedErrorList $recorded */ - public static function fromFilePutContentErrors(string $filename, array $recorded): self + public static function fromFilePutContentError(string $filename, Throwable $previous): self { - return new self(sprintf( - "Failed to write file %s.\n\nErrors:\n - %s", - $filename, - implode("\n - ", array_column($recorded, 'message')), - )); + return new self( + sprintf( + 'Failed to write file %s: %s', + $filename, + $previous->getMessage(), + ), + previous: $previous, + ); } - public static function fromNoPermissions(string $filename): self + public static function fromNoPermissions(string $filename, Throwable|null $previous): self { - return new self(sprintf( - 'Failed to write file %s as PIE does not have enough permissions', - $filename, - )); + return new self( + sprintf( + 'Failed to write file %s as PIE does not have enough permissions', + $filename, + ), + previous: $previous, + ); } } diff --git a/src/File/FullPathToSelf.php b/src/File/FullPathToSelf.php index f0fa3df6..d87f529c 100644 --- a/src/File/FullPathToSelf.php +++ b/src/File/FullPathToSelf.php @@ -8,8 +8,8 @@ use function array_key_exists; use function is_string; -use function preg_match; -use function realpath; +use function Safe\preg_match; +use function Safe\realpath; use const DIRECTORY_SEPARATOR; diff --git a/src/File/SudoCreate.php b/src/File/SudoCreate.php index 4f95bcf6..e56e5902 100644 --- a/src/File/SudoCreate.php +++ b/src/File/SudoCreate.php @@ -4,14 +4,14 @@ namespace Php\Pie\File; -use Php\Pie\Util\CaptureErrors; use Php\Pie\Util\Process; +use Safe\Exceptions\FilesystemException; use Symfony\Component\Process\Exception\ProcessFailedException; use function dirname; use function file_exists; use function is_writable; -use function touch; +use function Safe\touch; /** @internal This is not public API for PIE, so should not be depended upon unless you accept the risk of BC breaks */ final class SudoCreate @@ -33,14 +33,10 @@ public static function file(string $filename): void } if (is_writable(dirname($filename))) { - $capturedErrors = []; - $touchSuccessful = CaptureErrors::for( - static fn () => touch($filename), - $capturedErrors, - ); - - if (! $touchSuccessful) { - throw FailedToCreateFile::fromTouchErrors($filename, $capturedErrors); + try { + touch($filename); + } catch (FilesystemException $e) { + throw FailedToCreateFile::fromTouchError($filename, $e); } return; diff --git a/src/File/SudoFilePut.php b/src/File/SudoFilePut.php index c9fa6e34..0c64f655 100644 --- a/src/File/SudoFilePut.php +++ b/src/File/SudoFilePut.php @@ -4,17 +4,17 @@ namespace Php\Pie\File; -use Php\Pie\Util\CaptureErrors; use Php\Pie\Util\Process; +use Safe\Exceptions\FilesystemException; use Symfony\Component\Process\Exception\ProcessFailedException; use function dirname; use function file_exists; -use function file_put_contents; use function is_writable; -use function preg_match; +use function Safe\file_put_contents; +use function Safe\preg_match; +use function Safe\tempnam; use function sys_get_temp_dir; -use function tempnam; /** @internal This is not public API for PIE, so should not be depended upon unless you accept the risk of BC breaks */ final class SudoFilePut @@ -25,21 +25,17 @@ public static function contents(string $filename, string $content): void $pathWritable = ! file_exists($filename) && file_exists(dirname($filename)) && is_writable(dirname($filename)); if ($fileWritable || $pathWritable) { - $capturedErrors = []; - $writeSuccessful = CaptureErrors::for( - static fn () => file_put_contents($filename, $content), - $capturedErrors, - ); - - if ($writeSuccessful === false) { - throw FailedToWriteFile::fromFilePutContentErrors($filename, $capturedErrors); + try { + file_put_contents($filename, $content); + } catch (FilesystemException $e) { + throw FailedToWriteFile::fromFilePutContentError($filename, $e); } return; } if (! Sudo::exists()) { - throw FailedToWriteFile::fromNoPermissions($filename); + throw FailedToWriteFile::fromNoPermissions($filename, null); } self::writeWithSudo($filename, $content); @@ -47,19 +43,16 @@ public static function contents(string $filename, string $content): void private static function writeWithSudo(string $filename, string $content): void { - $tempFilename = tempnam(sys_get_temp_dir(), 'pie_tmp_'); - if ($tempFilename === false) { - throw FailedToWriteFile::fromNoPermissions($filename); + try { + $tempFilename = tempnam(sys_get_temp_dir(), 'pie_tmp_'); + } catch (FilesystemException $e) { + throw FailedToWriteFile::fromNoPermissions($filename, $e); } - $capturedErrors = []; - $writeSuccessful = CaptureErrors::for( - static fn () => file_put_contents($tempFilename, $content), - $capturedErrors, - ); - - if ($writeSuccessful === false) { - throw FailedToWriteFile::fromFilePutContentErrors($tempFilename, $capturedErrors); + try { + file_put_contents($tempFilename, $content); + } catch (FilesystemException $e) { + throw FailedToWriteFile::fromFilePutContentError($tempFilename, $e); } if (file_exists($filename)) { diff --git a/src/File/SudoUnlink.php b/src/File/SudoUnlink.php index 0e158ad4..0f983a64 100644 --- a/src/File/SudoUnlink.php +++ b/src/File/SudoUnlink.php @@ -5,13 +5,13 @@ namespace Php\Pie\File; use Composer\Util\Platform; -use Php\Pie\Util\CaptureErrors; use Php\Pie\Util\Process; +use Safe\Exceptions\FilesystemException; use Symfony\Component\Process\Exception\ProcessFailedException; use function file_exists; use function is_writable; -use function unlink; +use function Safe\unlink; /** @internal This is not public API for PIE, so should not be depended upon unless you accept the risk of BC breaks */ final class SudoUnlink @@ -23,14 +23,10 @@ public static function singleFile(string $filename): void } if (! Platform::isWindows() && is_writable($filename)) { - $capturedErrors = []; - $unlinkSuccessful = CaptureErrors::for( - static fn () => unlink($filename), - $capturedErrors, - ); - - if (! $unlinkSuccessful || file_exists($filename)) { - throw FailedToUnlinkFile::fromUnlinkErrors($filename, $capturedErrors); + try { + unlink($filename); + } catch (FilesystemException $e) { + throw FailedToUnlinkFile::fromUnlinkError($filename, $e); } return; diff --git a/src/File/WindowsDelete.php b/src/File/WindowsDelete.php index edae1ac5..9670d920 100644 --- a/src/File/WindowsDelete.php +++ b/src/File/WindowsDelete.php @@ -8,9 +8,9 @@ use RuntimeException; use function file_exists; +use function Safe\tempnam; use function sprintf; use function sys_get_temp_dir; -use function tempnam; /** @internal This is not public API for PIE, so should not be depended upon unless you accept the risk of BC breaks */ final class WindowsDelete @@ -27,12 +27,6 @@ public static function usingMoveToTemp(string $filename): void } $newLockedExtFilename = tempnam(sys_get_temp_dir(), 'pie'); - if ($newLockedExtFilename === false) { - throw new RuntimeException(sprintf( - 'Failed to create a temporary name for moving %s', - $filename, - )); - } Process::run(['move', $filename, $newLockedExtFilename]); diff --git a/src/Installing/Ini/AddExtensionToTheIniFile.php b/src/Installing/Ini/AddExtensionToTheIniFile.php index 14b7ba12..53a0cde1 100644 --- a/src/Installing/Ini/AddExtensionToTheIniFile.php +++ b/src/Installing/Ini/AddExtensionToTheIniFile.php @@ -10,12 +10,12 @@ use Php\Pie\File\Sudo; use Php\Pie\File\SudoFilePut; use Php\Pie\Platform\TargetPhp\PhpBinaryPath; +use Safe\Exceptions\FilesystemException; use Throwable; -use function file_get_contents; use function is_readable; -use function is_string; use function is_writable; +use function Safe\file_get_contents; use function sprintf; use const PHP_EOL; @@ -55,13 +55,14 @@ public function __invoke( return false; } - $originalIniContent = file_get_contents($ini); - - if (! is_string($originalIniContent)) { + try { + $originalIniContent = file_get_contents($ini); + } catch (FilesystemException $e) { $io->write( sprintf( - 'Tried making a backup of %s but could not read it, aborting enablement of extension', + 'Tried making a backup of %s but could not read it, aborting enablement of extension: %s', $ini, + $e->getMessage(), ), verbosity: IOInterface::VERBOSE, ); diff --git a/src/Installing/Ini/IsExtensionAlreadyInTheIniFile.php b/src/Installing/Ini/IsExtensionAlreadyInTheIniFile.php index cfe2c8bf..283bbfe9 100644 --- a/src/Installing/Ini/IsExtensionAlreadyInTheIniFile.php +++ b/src/Installing/Ini/IsExtensionAlreadyInTheIniFile.php @@ -5,13 +5,14 @@ namespace Php\Pie\Installing\Ini; use Php\Pie\ExtensionName; +use Webmozart\Assert\Assert; use function array_key_exists; use function array_merge; -use function file; use function in_array; use function is_string; -use function parse_ini_string; +use function Safe\file; +use function Safe\parse_ini_string; /** @internal This is not public API for PIE, so should not be depended upon unless you accept the risk of BC breaks */ class IsExtensionAlreadyInTheIniFile @@ -31,6 +32,7 @@ private function readIniFile(string $iniFilePath): array $extensions = []; $zendExtensions = []; foreach ($iniFileContentLines as $line) { + Assert::string($line); $lineIni = parse_ini_string($line); if (array_key_exists('extension', $lineIni) && is_string($lineIni['extension']) && $lineIni['extension'] !== '') { diff --git a/src/Installing/Ini/OndrejPhpenmod.php b/src/Installing/Ini/OndrejPhpenmod.php index 62c2b256..9048ea79 100644 --- a/src/Installing/Ini/OndrejPhpenmod.php +++ b/src/Installing/Ini/OndrejPhpenmod.php @@ -19,8 +19,8 @@ use function file_exists; use function is_dir; use function is_writable; -use function preg_match; use function rtrim; +use function Safe\preg_match; use function sprintf; use const DIRECTORY_SEPARATOR; diff --git a/src/Installing/Ini/RemoveIniEntryWithFileGetContents.php b/src/Installing/Ini/RemoveIniEntryWithFileGetContents.php index 8b39a8d5..96abe3e6 100644 --- a/src/Installing/Ini/RemoveIniEntryWithFileGetContents.php +++ b/src/Installing/Ini/RemoveIniEntryWithFileGetContents.php @@ -10,18 +10,18 @@ use Php\Pie\File\FailedToWriteFile; use Php\Pie\File\SudoFilePut; use Php\Pie\Platform\TargetPlatform; +use Webmozart\Assert\Assert; use function array_filter; use function array_map; use function array_merge; use function array_walk; use function file_exists; -use function file_get_contents; use function in_array; -use function is_array; use function is_dir; -use function preg_replace; -use function scandir; +use function Safe\file_get_contents; +use function Safe\preg_replace; +use function Safe\scandir; use function sprintf; use const DIRECTORY_SEPARATOR; @@ -42,26 +42,26 @@ public function __invoke(Package $package, TargetPlatform $targetPlatform, IOInt $additionalIniDirectory = $targetPlatform->phpBinaryPath->additionalIniDirectory(); if ($additionalIniDirectory !== null && file_exists($additionalIniDirectory) && is_dir($additionalIniDirectory)) { $filenames = scandir($additionalIniDirectory); - if (is_array($filenames)) { - $allIniFiles = array_merge( - array_map( - static function (string $path) use ($additionalIniDirectory): string { - return $additionalIniDirectory . DIRECTORY_SEPARATOR . $path; + Assert::isList($filenames); + Assert::allString($filenames); + $allIniFiles = array_merge( + array_map( + static function (string $path) use ($additionalIniDirectory): string { + return $additionalIniDirectory . DIRECTORY_SEPARATOR . $path; + }, + array_filter( + $filenames, + static function (string $path) use ($additionalIniDirectory): bool { + if (in_array($path, ['.', '..'])) { + return false; + } + + return file_exists($additionalIniDirectory . DIRECTORY_SEPARATOR . $path); }, - array_filter( - $filenames, - static function (string $path) use ($additionalIniDirectory): bool { - if (in_array($path, ['.', '..'])) { - return false; - } - - return file_exists($additionalIniDirectory . DIRECTORY_SEPARATOR . $path); - }, - ), ), - $allIniFiles, - ); - } + ), + $allIniFiles, + ); } // Make sure all symlinks are resolved @@ -79,7 +79,7 @@ static function (string $path) use ($additionalIniDirectory): bool { static function (string $iniFile) use (&$updatedIniFiles, $regex, $package, $io): void { $currentContent = file_get_contents($iniFile); - if ($currentContent === false || $currentContent === '') { + if ($currentContent === '') { return; } @@ -89,7 +89,7 @@ static function (string $iniFile) use (&$updatedIniFiles, $regex, $package, $io) $currentContent, ); - if ($replacedContent === null || $replacedContent === $currentContent) { + if ($replacedContent === $currentContent) { return; } diff --git a/src/Installing/WindowsInstall.php b/src/Installing/WindowsInstall.php index e674a561..21a7f5e4 100644 --- a/src/Installing/WindowsInstall.php +++ b/src/Installing/WindowsInstall.php @@ -16,11 +16,11 @@ use SplFileInfo; use function assert; -use function copy; use function dirname; use function file_exists; use function is_file; -use function mkdir; +use function Safe\copy; +use function Safe\mkdir; use function str_replace; use function strlen; use function substr; @@ -117,7 +117,9 @@ private function copyExtensionDll(TargetPlatform $targetPlatform, DownloadedPack WindowsDelete::usingMoveToTemp($destinationDllName); } - if (! copy($sourceDllName, $destinationDllName) || ! file_exists($destinationDllName) && ! is_file($destinationDllName)) { + copy($sourceDllName, $destinationDllName); + + if (! file_exists($destinationDllName) && ! is_file($destinationDllName)) { throw new RuntimeException('Failed to install DLL to ' . $destinationDllName); } @@ -144,7 +146,9 @@ private function copyExtensionPdb(TargetPlatform $targetPlatform, DownloadedPack $destinationPdbName = str_replace('.dll', '.pdb', $destinationDllName); assert($destinationPdbName !== ''); - if (! copy($sourcePdbName, $destinationPdbName) || ! file_exists($destinationPdbName) && ! is_file($destinationPdbName)) { + copy($sourcePdbName, $destinationPdbName); + + if (! file_exists($destinationPdbName) && ! is_file($destinationPdbName)) { throw new RuntimeException('Failed to install PDB to ' . $destinationPdbName); } @@ -167,7 +171,9 @@ private function copyDependencyDll(TargetPlatform $targetPlatform, SplFileInfo $ $destinationExtraDll = dirname($targetPlatform->phpBinaryPath->phpBinaryPath) . DIRECTORY_SEPARATOR . $file->getFilename(); - if (! copy($file->getPathname(), $destinationExtraDll) || ! file_exists($destinationExtraDll) && ! is_file($destinationExtraDll)) { + copy($file->getPathname(), $destinationExtraDll); + + if (! file_exists($destinationExtraDll) && ! is_file($destinationExtraDll)) { throw new RuntimeException('Failed to copy to ' . $destinationExtraDll); } @@ -192,7 +198,9 @@ private function copyExtraFile(TargetPlatform $targetPlatform, DownloadedPackage mkdir($destinationPath, 0777, true); } - if (! copy($file->getPathname(), $destinationFullFilename) || ! file_exists($destinationFullFilename) && ! is_file($destinationFullFilename)) { + copy($file->getPathname(), $destinationFullFilename); + + if (! file_exists($destinationFullFilename) && ! is_file($destinationFullFilename)) { throw new RuntimeException('Failed to copy to ' . $destinationFullFilename); } diff --git a/src/Platform.php b/src/Platform.php index 4abeb709..e2a3f778 100644 --- a/src/Platform.php +++ b/src/Platform.php @@ -8,13 +8,14 @@ use Composer\Util\Silencer; use Php\Pie\Platform\TargetPlatform; use RuntimeException; +use Safe\Exceptions\FilesystemException; use function array_keys; use function defined; -use function fopen; use function implode; use function md5; use function rtrim; +use function Safe\fopen; use function str_contains; use function strpos; use function strtr; @@ -28,7 +29,11 @@ class Platform { public static function isInteractive(): bool { - $stdin = defined('STDIN') ? STDIN : fopen('php://stdin', 'r'); + try { + $stdin = defined('STDIN') ? STDIN : fopen('php://stdin', 'r'); + } catch (FilesystemException) { + $stdin = false; + } return ComposerPlatform::getEnv('COMPOSER_NO_INTERACTION') !== '1' && $stdin !== false diff --git a/src/Platform/TargetPhp/PhpBinaryPath.php b/src/Platform/TargetPhp/PhpBinaryPath.php index 5a6c67ec..7f001a4f 100644 --- a/src/Platform/TargetPhp/PhpBinaryPath.php +++ b/src/Platform/TargetPhp/PhpBinaryPath.php @@ -15,6 +15,7 @@ use Php\Pie\Platform\TargetPhp\Exception\ExtensionPathProblem; use Php\Pie\Util\Process; use RuntimeException; +use Safe\Exceptions\FilesystemException; use Symfony\Component\Process\PhpExecutableFinder; use Webmozart\Assert\Assert; @@ -32,10 +33,10 @@ use function is_dir; use function is_executable; use function ltrim; -use function mkdir; -use function preg_match; -use function preg_replace; use function rtrim; +use function Safe\mkdir; +use function Safe\preg_match; +use function Safe\preg_replace; use function sprintf; use function strtolower; use function trim; @@ -139,7 +140,13 @@ public function extensionPath(string|null $prefixInstallRoot = null): string } // if the path is absolute, try to create it - if (mkdir($extensionPath, 0777, true) && file_exists($extensionPath) && is_dir($extensionPath)) { + try { + mkdir($extensionPath, 0777, true); + } catch (FilesystemException) { + throw ExtensionPathProblem::new($this, $extensionPath); + } + + if (file_exists($extensionPath) && is_dir($extensionPath)) { return $extensionPath; } } @@ -495,7 +502,6 @@ private static function guessWithPhpConfig(self $phpBinaryPath): self $phpConfigAttempts[] = preg_replace('((.*)php)', '$1php-config', $phpBinaryPath->phpBinaryPath); foreach ($phpConfigAttempts as $phpConfigAttempt) { - assert($phpConfigAttempt !== null); assert($phpConfigAttempt !== ''); if (! file_exists($phpConfigAttempt) || ! is_executable($phpConfigAttempt)) { continue; diff --git a/src/Platform/TargetPhp/PhpizePath.php b/src/Platform/TargetPhp/PhpizePath.php index 8112d70c..c3ae5a7a 100644 --- a/src/Platform/TargetPhp/PhpizePath.php +++ b/src/Platform/TargetPhp/PhpizePath.php @@ -10,8 +10,8 @@ use function assert; use function file_exists; use function is_executable; -use function preg_match; -use function preg_replace; +use function Safe\preg_match; +use function Safe\preg_replace; use function trim; /** @@ -68,7 +68,6 @@ public static function guessFrom(PhpBinaryPath $phpBinaryPath): self $phpizeAttempts[] = preg_replace('((.*)php)', '$1phpize', $phpBinaryPath->phpBinaryPath); foreach ($phpizeAttempts as $phpizeAttempt) { - assert($phpizeAttempt !== null); assert($phpizeAttempt !== ''); if (self::looksLikeValidPhpize($phpizeAttempt, $expectedApiVersion)) { diff --git a/src/Platform/TargetPlatform.php b/src/Platform/TargetPlatform.php index e6eb7cae..1b8d25ef 100644 --- a/src/Platform/TargetPlatform.php +++ b/src/Platform/TargetPlatform.php @@ -11,7 +11,7 @@ use function explode; use function function_exists; use function posix_getuid; -use function preg_match; +use function Safe\preg_match; use function trim; /** diff --git a/src/SelfManage/Update/FetchPieReleaseFromGitHub.php b/src/SelfManage/Update/FetchPieReleaseFromGitHub.php index 9b03ee77..4973f45e 100644 --- a/src/SelfManage/Update/FetchPieReleaseFromGitHub.php +++ b/src/SelfManage/Update/FetchPieReleaseFromGitHub.php @@ -8,16 +8,18 @@ use Composer\Util\HttpDownloader; use Php\Pie\File\BinaryFile; use RuntimeException; +use Safe\Exceptions\FilesystemException; use Webmozart\Assert\Assert; use function array_filter; use function array_key_exists; use function array_map; use function count; -use function file_put_contents; use function reset; +use function Safe\file_put_contents; +use function Safe\tempnam; +use function sprintf; use function sys_get_temp_dir; -use function tempnam; /** @internal This is not public API for PIE, so should not be depended upon unless you accept the risk of BC breaks */ final class FetchPieReleaseFromGitHub implements FetchPieRelease @@ -127,10 +129,18 @@ public function downloadContent(ReleaseMetadata $releaseMetadata): BinaryFile Assert::stringNotEmpty($pharContent); $tempPharFilename = tempnam(sys_get_temp_dir(), 'pie_self_update_'); - Assert::stringNotEmpty($tempPharFilename); - if (file_put_contents($tempPharFilename, $pharContent) === false) { - throw new RuntimeException('Failed to write downloaded PHAR to ' . $tempPharFilename); + try { + file_put_contents($tempPharFilename, $pharContent); + } catch (FilesystemException $previous) { + throw new RuntimeException( + sprintf( + 'Failed to write downloaded PHAR to %s: %s', + $tempPharFilename, + $previous->getMessage(), + ), + previous: $previous, + ); } return BinaryFile::fromFileWithSha256Checksum($tempPharFilename); diff --git a/src/SelfManage/Update/ReleaseIsNewer.php b/src/SelfManage/Update/ReleaseIsNewer.php index 6c1b9b20..e183e655 100644 --- a/src/SelfManage/Update/ReleaseIsNewer.php +++ b/src/SelfManage/Update/ReleaseIsNewer.php @@ -7,7 +7,7 @@ use Composer\Semver\Semver; use Composer\Semver\VersionParser; -use function preg_match; +use function Safe\preg_match; use function strtolower; /** @internal This is not public API for PIE, so should not be depended upon unless you accept the risk of BC breaks */ diff --git a/src/SelfManage/Verify/Attestation.php b/src/SelfManage/Verify/Attestation.php index 6664cc6a..503af12f 100644 --- a/src/SelfManage/Verify/Attestation.php +++ b/src/SelfManage/Verify/Attestation.php @@ -6,7 +6,7 @@ use Webmozart\Assert\Assert; -use function base64_decode; +use function Safe\base64_decode; use function wordwrap; /** @internal This is not public API for PIE, so should not be depended upon unless you accept the risk of BC breaks */ diff --git a/src/Settings.php b/src/Settings.php index 5b78fdbe..0ab37035 100644 --- a/src/Settings.php +++ b/src/Settings.php @@ -9,12 +9,12 @@ use function array_key_exists; use function file_exists; -use function file_get_contents; -use function file_put_contents; use function json_decode; use function json_encode; -use function mkdir; use function rtrim; +use function Safe\file_get_contents; +use function Safe\file_put_contents; +use function Safe\mkdir; use const DIRECTORY_SEPARATOR; use const JSON_PRETTY_PRINT; @@ -67,7 +67,7 @@ private function read(): array } $content = file_get_contents($pieSettingsFileName); - if ($content === false) { + if ($content === '') { return []; } diff --git a/src/Util/CaptureErrors.php b/src/Util/CaptureErrors.php deleted file mode 100644 index 2873d8b8..00000000 --- a/src/Util/CaptureErrors.php +++ /dev/null @@ -1,44 +0,0 @@ - - */ -final class CaptureErrors -{ - /** - * @param callable():T $code - * @param CapturedErrorList $captured - * - * @return T - * - * @template T - */ - public static function for(callable $code, array &$captured): mixed - { - set_error_handler(static function (int $level, string $message, string $filename, int $line) use (&$captured): bool { - $captured[] = [ - 'level' => $level, - 'message' => $message, - 'filename' => $filename, - 'line' => $line, - ]; - - return true; - }); - - $returnValue = $code(); - - restore_error_handler(); - - return $returnValue; - } -} diff --git a/src/Util/ProcessFailedWithLimitedOutput.php b/src/Util/ProcessFailedWithLimitedOutput.php index afebda2f..09489eef 100644 --- a/src/Util/ProcessFailedWithLimitedOutput.php +++ b/src/Util/ProcessFailedWithLimitedOutput.php @@ -7,7 +7,7 @@ use Symfony\Component\Process\Exception\ProcessFailedException; use Symfony\Component\Process\Process; -use function file_put_contents; +use function Safe\file_put_contents; use function sprintf; use function strlen; use function sys_get_temp_dir; diff --git a/test/behaviour/CliContext.php b/test/behaviour/CliContext.php index c39b00bf..47617655 100644 --- a/test/behaviour/CliContext.php +++ b/test/behaviour/CliContext.php @@ -14,8 +14,8 @@ use function array_merge; use function assert; -use function copy; -use function realpath; +use function Safe\copy; +use function Safe\realpath; use function sprintf; use function str_contains; @@ -352,10 +352,7 @@ public function iAmInAPHPProjectThatHasMissingExtensions(): void $this->assertCommandSuccessful(); Assert::notContains($this->output, 'example_pie_extension'); - $examplePhpProject = (string) realpath(__DIR__ . '/../assets/example-php-project'); - assert($examplePhpProject !== ''); - - $this->workingDirectory = $examplePhpProject; + $this->workingDirectory = realpath(__DIR__ . '/../assets/example-php-project'); } #[When('I run a command to install the extensions')] @@ -379,10 +376,7 @@ public function iShouldSeeAllTheExtensionsAreNowInstalled(): void #[Given('I am in a PIE project')] public function iAmInAPIEProject(): void { - $examplePieProject = (string) realpath('/example-pie-extension'); - assert($examplePieProject !== ''); - - $this->workingDirectory = $examplePieProject; + $this->workingDirectory = realpath('/example-pie-extension'); } #[When('I run a command to install the extension')] diff --git a/test/integration/Command/CommandTester.php b/test/integration/Command/CommandTester.php index d52ff63e..1ab0779e 100644 --- a/test/integration/Command/CommandTester.php +++ b/test/integration/Command/CommandTester.php @@ -11,7 +11,7 @@ use Symfony\Component\Console\Tester\CommandTester as SymfonyCommandTester; use function assert; -use function ftruncate; +use function Safe\ftruncate; class CommandTester extends SymfonyCommandTester { diff --git a/test/integration/Command/InstallCommandTest.php b/test/integration/Command/InstallCommandTest.php index dd39e533..9ba63c84 100644 --- a/test/integration/Command/InstallCommandTest.php +++ b/test/integration/Command/InstallCommandTest.php @@ -25,7 +25,7 @@ use function is_file; use function is_string; use function is_writable; -use function preg_match; +use function Safe\preg_match; #[CoversClass(InstallCommand::class)] class InstallCommandTest extends TestCase diff --git a/test/integration/Command/InstallExtensionsForProjectCommandTest.php b/test/integration/Command/InstallExtensionsForProjectCommandTest.php index ad9f6cfa..ae1833d5 100644 --- a/test/integration/Command/InstallExtensionsForProjectCommandTest.php +++ b/test/integration/Command/InstallExtensionsForProjectCommandTest.php @@ -37,7 +37,7 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\BufferedOutput; -use function getcwd; +use function Safe\getcwd; #[CoversClass(InstallExtensionsForProjectCommand::class)] final class InstallExtensionsForProjectCommandTest extends TestCase diff --git a/test/integration/Installing/UnixInstallTest.php b/test/integration/Installing/UnixInstallTest.php index f3b6ba09..435f0664 100644 --- a/test/integration/Installing/UnixInstallTest.php +++ b/test/integration/Installing/UnixInstallTest.php @@ -34,9 +34,9 @@ use function getenv; use function is_executable; use function is_writable; -use function mkdir; -use function putenv; -use function rename; +use function Safe\mkdir; +use function Safe\putenv; +use function Safe\rename; use function uniqid; use const DIRECTORY_SEPARATOR; @@ -186,11 +186,14 @@ public function testUnixInstallCanInstallPrePackagedBinary(string $phpConfig): v $output, ); + if (! file_exists(self::TEST_PREBUILT_PATH)) { + mkdir(self::TEST_PREBUILT_PATH, 0777, true); + } + /** * Move the built .so into a new path; this simulates a pre-packaged binary, which would not have Makefile etc * so this ensures we're not accidentally relying on any build mechanism (`make install` or otherwise) */ - mkdir(self::TEST_PREBUILT_PATH, 0777, true); $prebuiltBinaryFilePath = self::TEST_PREBUILT_PATH . DIRECTORY_SEPARATOR . 'pie_test_ext.so'; rename($built->filePath, $prebuiltBinaryFilePath); diff --git a/test/integration/Installing/WindowsInstallTest.php b/test/integration/Installing/WindowsInstallTest.php index 56384135..db18553d 100644 --- a/test/integration/Installing/WindowsInstallTest.php +++ b/test/integration/Installing/WindowsInstallTest.php @@ -31,9 +31,9 @@ use function dirname; use function file_exists; use function is_dir; -use function rmdir; +use function Safe\rmdir; +use function Safe\unlink; use function str_replace; -use function unlink; use const DIRECTORY_SEPARATOR; diff --git a/test/unit/Building/PlaceholderReplacerTest.php b/test/unit/Building/PlaceholderReplacerTest.php index 7be851e1..17658f5c 100644 --- a/test/unit/Building/PlaceholderReplacerTest.php +++ b/test/unit/Building/PlaceholderReplacerTest.php @@ -7,7 +7,6 @@ use Composer\IO\IOInterface; use Composer\Package\CompletePackage; use Composer\Util\Filesystem; -use DateTimeImmutable; use Php\Pie\Building\PlaceholderReplacer; use Php\Pie\DependencyResolver\Package; use Php\Pie\Downloading\DownloadedPackage; @@ -19,6 +18,7 @@ use Php\Pie\Platform\ThreadSafetyMode; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; +use Safe\DateTimeImmutable; use function Safe\file_get_contents; use function Safe\file_put_contents; diff --git a/test/unit/ComposerIntegration/BundledPhpExtensionsRepositoryTest.php b/test/unit/ComposerIntegration/BundledPhpExtensionsRepositoryTest.php index 5117d4ff..e66b926f 100644 --- a/test/unit/ComposerIntegration/BundledPhpExtensionsRepositoryTest.php +++ b/test/unit/ComposerIntegration/BundledPhpExtensionsRepositoryTest.php @@ -22,8 +22,8 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Process\Exception\ProcessFailedException; -use function mkdir; -use function realpath; +use function Safe\mkdir; +use function Safe\realpath; use function sys_get_temp_dir; use function uniqid; diff --git a/test/unit/ComposerIntegration/PieJsonEditorTest.php b/test/unit/ComposerIntegration/PieJsonEditorTest.php index 57fa7e6a..c1ca87ce 100644 --- a/test/unit/ComposerIntegration/PieJsonEditorTest.php +++ b/test/unit/ComposerIntegration/PieJsonEditorTest.php @@ -9,10 +9,10 @@ use PHPUnit\Framework\TestCase; use function dirname; -use function file_get_contents; -use function file_put_contents; -use function json_decode; -use function json_encode; +use function Safe\file_get_contents; +use function Safe\file_put_contents; +use function Safe\json_decode; +use function Safe\json_encode; use function sys_get_temp_dir; use function uniqid; diff --git a/test/unit/ComposerIntegration/VendorCleanupTest.php b/test/unit/ComposerIntegration/VendorCleanupTest.php index 0336f9b0..77719985 100644 --- a/test/unit/ComposerIntegration/VendorCleanupTest.php +++ b/test/unit/ComposerIntegration/VendorCleanupTest.php @@ -58,7 +58,7 @@ public function testInvalidVendorDirectory(): void ->expects(self::once()) ->method('write') ->with( - 'Vendor directory (vendor-dir config) /path/that/does/not/exist seemed invalid?', + 'Vendor directory (vendor-dir config) /path/that/does/not/exist seemed invalid? An error occurred', true, IOInterface::VERY_VERBOSE, ); diff --git a/test/unit/Downloading/DownloadedPackageTest.php b/test/unit/Downloading/DownloadedPackageTest.php index ea8b306c..67f51196 100644 --- a/test/unit/Downloading/DownloadedPackageTest.php +++ b/test/unit/Downloading/DownloadedPackageTest.php @@ -12,7 +12,7 @@ use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; -use function realpath; +use function Safe\realpath; use function uniqid; use const DIRECTORY_SEPARATOR; diff --git a/test/unit/File/SudoCreateTest.php b/test/unit/File/SudoCreateTest.php index d37362cb..c681b950 100644 --- a/test/unit/File/SudoCreateTest.php +++ b/test/unit/File/SudoCreateTest.php @@ -10,8 +10,8 @@ use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; -use function chmod; -use function mkdir; +use function Safe\chmod; +use function Safe\mkdir; use function sys_get_temp_dir; use function uniqid; diff --git a/test/unit/File/SudoFilePutTest.php b/test/unit/File/SudoFilePutTest.php index 96f866b0..2d82cf79 100644 --- a/test/unit/File/SudoFilePutTest.php +++ b/test/unit/File/SudoFilePutTest.php @@ -10,11 +10,11 @@ use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; -use function chmod; -use function file_get_contents; -use function mkdir; +use function Safe\chmod; +use function Safe\file_get_contents; +use function Safe\mkdir; +use function Safe\touch; use function sys_get_temp_dir; -use function touch; use function uniqid; use const DIRECTORY_SEPARATOR; diff --git a/test/unit/File/SudoUnlinkTest.php b/test/unit/File/SudoUnlinkTest.php index 77fa0443..5a888e05 100644 --- a/test/unit/File/SudoUnlinkTest.php +++ b/test/unit/File/SudoUnlinkTest.php @@ -9,9 +9,9 @@ use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; -use function chmod; +use function Safe\chmod; +use function Safe\touch; use function sys_get_temp_dir; -use function touch; use function uniqid; use const DIRECTORY_SEPARATOR; diff --git a/test/unit/Installing/Ini/AddExtensionToTheIniFileTest.php b/test/unit/Installing/Ini/AddExtensionToTheIniFileTest.php index afe7a9b9..39418219 100644 --- a/test/unit/Installing/Ini/AddExtensionToTheIniFileTest.php +++ b/test/unit/Installing/Ini/AddExtensionToTheIniFileTest.php @@ -20,14 +20,14 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Console\Output\OutputInterface; -use function chmod; -use function file_get_contents; -use function file_put_contents; +use function Safe\chmod; +use function Safe\file_get_contents; +use function Safe\file_put_contents; +use function Safe\tempnam; +use function Safe\touch; +use function Safe\unlink; use function sprintf; use function sys_get_temp_dir; -use function tempnam; -use function touch; -use function unlink; use const PHP_EOL; diff --git a/test/unit/Installing/Ini/OndrejPhpenmodTest.php b/test/unit/Installing/Ini/OndrejPhpenmodTest.php index 39c311d9..2a6fe1f9 100644 --- a/test/unit/Installing/Ini/OndrejPhpenmodTest.php +++ b/test/unit/Installing/Ini/OndrejPhpenmodTest.php @@ -27,11 +27,11 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Console\Output\OutputInterface; -use function mkdir; -use function rmdir; +use function Safe\mkdir; +use function Safe\rmdir; +use function Safe\tempnam; +use function Safe\unlink; use function sys_get_temp_dir; -use function tempnam; -use function unlink; use const DIRECTORY_SEPARATOR; diff --git a/test/unit/Installing/Ini/RemoveIniEntryWithFileGetContentsTest.php b/test/unit/Installing/Ini/RemoveIniEntryWithFileGetContentsTest.php index ef571853..16d398b2 100644 --- a/test/unit/Installing/Ini/RemoveIniEntryWithFileGetContentsTest.php +++ b/test/unit/Installing/Ini/RemoveIniEntryWithFileGetContentsTest.php @@ -23,16 +23,16 @@ use PHPUnit\Framework\TestCase; use Webmozart\Assert\Assert; -use function file_get_contents; -use function file_put_contents; use function is_link; -use function mkdir; -use function realpath; -use function symlink; +use function Safe\file_get_contents; +use function Safe\file_put_contents; +use function Safe\mkdir; +use function Safe\realpath; +use function Safe\symlink; +use function Safe\tempnam; +use function Safe\unlink; use function sys_get_temp_dir; -use function tempnam; use function uniqid; -use function unlink; use const DIRECTORY_SEPARATOR; diff --git a/test/unit/Installing/Ini/StandardAdditionalPhpIniDirectoryTest.php b/test/unit/Installing/Ini/StandardAdditionalPhpIniDirectoryTest.php index f6113cae..50e80aa9 100644 --- a/test/unit/Installing/Ini/StandardAdditionalPhpIniDirectoryTest.php +++ b/test/unit/Installing/Ini/StandardAdditionalPhpIniDirectoryTest.php @@ -24,12 +24,12 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Console\Output\OutputInterface; -use function mkdir; -use function rmdir; +use function Safe\mkdir; +use function Safe\rmdir; +use function Safe\tempnam; +use function Safe\touch; +use function Safe\unlink; use function sys_get_temp_dir; -use function tempnam; -use function touch; -use function unlink; use const DIRECTORY_SEPARATOR; diff --git a/test/unit/Installing/UninstallUsingUnlinkTest.php b/test/unit/Installing/UninstallUsingUnlinkTest.php index 8b928d14..28b93815 100644 --- a/test/unit/Installing/UninstallUsingUnlinkTest.php +++ b/test/unit/Installing/UninstallUsingUnlinkTest.php @@ -14,8 +14,8 @@ use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; -use function file_put_contents; -use function hash_file; +use function Safe\file_put_contents; +use function Safe\hash_file; use function sys_get_temp_dir; use function uniqid; diff --git a/test/unit/Platform/LibcFlavourTest.php b/test/unit/Platform/LibcFlavourTest.php index 231462e8..5f5ca4ef 100644 --- a/test/unit/Platform/LibcFlavourTest.php +++ b/test/unit/Platform/LibcFlavourTest.php @@ -10,8 +10,8 @@ use PHPUnit\Framework\TestCase; use function getenv; -use function putenv; -use function realpath; +use function Safe\putenv; +use function Safe\realpath; use const PATH_SEPARATOR; diff --git a/test/unit/Platform/TargetPhp/PhpBinaryPathTest.php b/test/unit/Platform/TargetPhp/PhpBinaryPathTest.php index 64151b07..95275522 100644 --- a/test/unit/Platform/TargetPhp/PhpBinaryPathTest.php +++ b/test/unit/Platform/TargetPhp/PhpBinaryPathTest.php @@ -30,25 +30,25 @@ use function array_map; use function array_unique; use function assert; -use function chmod; use function count; use function defined; use function dirname; use function file_exists; -use function file_put_contents; use function get_loaded_extensions; -use function ini_get; use function is_dir; use function is_executable; -use function mkdir; use function phpversion; +use function Safe\chmod; +use function Safe\file_put_contents; +use function Safe\ini_get; +use function Safe\mkdir; +use function Safe\tempnam; +use function Safe\unlink; use function sprintf; use function strtolower; use function sys_get_temp_dir; -use function tempnam; use function trim; use function uniqid; -use function unlink; use const DIRECTORY_SEPARATOR; use const PHP_INT_SIZE; diff --git a/test/unit/SelfManage/BuildTools/PhpizeBuildToolFinderTest.php b/test/unit/SelfManage/BuildTools/PhpizeBuildToolFinderTest.php index 4db05eeb..f681073a 100644 --- a/test/unit/SelfManage/BuildTools/PhpizeBuildToolFinderTest.php +++ b/test/unit/SelfManage/BuildTools/PhpizeBuildToolFinderTest.php @@ -17,8 +17,8 @@ use PHPUnit\Framework\TestCase; use function getenv; -use function putenv; -use function realpath; +use function Safe\putenv; +use function Safe\realpath; use const DIRECTORY_SEPARATOR; @@ -64,7 +64,6 @@ public function testCheckWithPhpizeFromTargetPlatform(): void ->bindTo($mockPhpBinary, PhpBinaryPath::class)(); $goodPhpize = realpath(self::GOOD_PHPIZE_PATH . DIRECTORY_SEPARATOR . 'phpize'); - self::assertNotFalse($goodPhpize); self::assertTrue((new PhpizeBuildToolFinder([]))->check(new TargetPlatform( OperatingSystem::NonWindows, @@ -117,7 +116,6 @@ public function testPhpizeForDifferentPhpApiVersionIsRejected(): void ->bindTo($mockPhpBinary, PhpBinaryPath::class)(); $goodPhpize = realpath(self::GOOD_PHPIZE_PATH . DIRECTORY_SEPARATOR . 'phpize'); - self::assertNotFalse($goodPhpize); self::assertFalse((new PhpizeBuildToolFinder([]))->check(new TargetPlatform( OperatingSystem::NonWindows, diff --git a/test/unit/SelfManage/Update/FetchPieReleaseFromGitHubTest.php b/test/unit/SelfManage/Update/FetchPieReleaseFromGitHubTest.php index 840ec7a6..009dda2e 100644 --- a/test/unit/SelfManage/Update/FetchPieReleaseFromGitHubTest.php +++ b/test/unit/SelfManage/Update/FetchPieReleaseFromGitHubTest.php @@ -13,9 +13,9 @@ use PHPUnit\Framework\TestCase; use RuntimeException; -use function file_get_contents; use function hash; -use function json_encode; +use function Safe\file_get_contents; +use function Safe\json_encode; use function uniqid; #[CoversClass(FetchPieReleaseFromGitHub::class)] diff --git a/test/unit/SelfManage/Verify/FallbackVerificationUsingOpenSslTest.php b/test/unit/SelfManage/Verify/FallbackVerificationUsingOpenSslTest.php index b58e3331..af2b7d9a 100644 --- a/test/unit/SelfManage/Verify/FallbackVerificationUsingOpenSslTest.php +++ b/test/unit/SelfManage/Verify/FallbackVerificationUsingOpenSslTest.php @@ -8,6 +8,8 @@ use Composer\IO\BufferIO; use Composer\Util\Http\Response; use Composer\Util\HttpDownloader; +use OpenSSLAsymmetricKey; +use OpenSSLCertificateSigningRequest; use Php\Pie\File\BinaryFile; use Php\Pie\SelfManage\Update\ReleaseMetadata; use Php\Pie\SelfManage\Verify\FailedToVerifyRelease; @@ -20,19 +22,18 @@ use function assert; use function base64_encode; use function extension_loaded; -use function file_put_contents; -use function is_string; -use function json_encode; -use function openssl_csr_new; -use function openssl_csr_sign; -use function openssl_pkey_new; -use function openssl_sign; -use function openssl_x509_export; +use function Safe\file_put_contents; +use function Safe\json_encode; +use function Safe\openssl_csr_new; +use function Safe\openssl_csr_sign; +use function Safe\openssl_pkey_new; +use function Safe\openssl_sign; +use function Safe\openssl_x509_export; +use function Safe\tempnam; use function sprintf; use function str_replace; use function strlen; use function sys_get_temp_dir; -use function tempnam; use function trim; use const OPENSSL_ALGO_SHA256; @@ -61,8 +62,7 @@ public function setUp(): void $this->httpDownloader = $this->createMock(HttpDownloader::class); $this->io = new BufferIO(); - $trustedRootFilePath = tempnam(sys_get_temp_dir(), 'pie_test_trusted_root_file_path'); - assert(is_string($trustedRootFilePath)); + $trustedRootFilePath = tempnam(sys_get_temp_dir(), 'pie_test_trusted_root_file_path'); $this->trustedRootFilePath = $trustedRootFilePath; $this->verifier = new FallbackVerificationUsingOpenSsl(new VerifyAttestationWithOpenSsl($this->trustedRootFilePath, self::TEST_GITHUB_URL, $this->httpDownloader)); @@ -73,8 +73,11 @@ private function prepareCertificateAndSignature(string $dsseEnvelopePayload): ar { $caPrivateKey = openssl_pkey_new(); $caCsr = openssl_csr_new(['CN' => 'pie-test-ca'], $caPrivateKey); - $caCert = openssl_csr_sign($caCsr, null, $caPrivateKey, 1); + assert($caCsr instanceof OpenSSLCertificateSigningRequest); + assert($caPrivateKey instanceof OpenSSLAsymmetricKey); + $caCert = openssl_csr_sign($caCsr, null, $caPrivateKey, 1); openssl_x509_export($caCert, $caPemCertificate); + assert($caPemCertificate !== null); file_put_contents($this->trustedRootFilePath, json_encode([ 'mediaType' => 'application/vnd.dev.sigstore.trustedroot+json;version=0.1', @@ -109,13 +112,16 @@ private function prepareCertificateAndSignature(string $dsseEnvelopePayload): ar 1.3.6.1.4.1.57264.1.12 = ASN1:UTF8String:https://github.com/php/pie 1.3.6.1.4.1.57264.1.16 = ASN1:UTF8String:https://github.com/php EOF); - $privateKey = openssl_pkey_new(); - $csr = openssl_csr_new(['commonName' => 'pie-test'], $privateKey, ['config' => $tempOpensslConfig]); + $privateKey = openssl_pkey_new(); + $csr = openssl_csr_new(['commonName' => 'pie-test'], $privateKey, ['config' => $tempOpensslConfig]); + assert($csr instanceof OpenSSLCertificateSigningRequest); $certificate = openssl_csr_sign($csr, $caCert, $caPrivateKey, 1, [ 'config' => $tempOpensslConfig, 'x509_extensions' => 'v3_req', ]); openssl_x509_export($certificate, $pemCertificate); + assert($pemCertificate !== null); + assert($privateKey !== null); openssl_sign( sprintf( @@ -129,6 +135,7 @@ private function prepareCertificateAndSignature(string $dsseEnvelopePayload): ar $privateKey, OPENSSL_ALGO_SHA256, ); + assert($signature !== null); return [$pemCertificate, $signature]; } diff --git a/test/unit/SettingsTest.php b/test/unit/SettingsTest.php index db28700e..2727f4c2 100644 --- a/test/unit/SettingsTest.php +++ b/test/unit/SettingsTest.php @@ -11,9 +11,9 @@ use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; -use function file_get_contents; -use function file_put_contents; -use function mkdir; +use function Safe\file_get_contents; +use function Safe\file_put_contents; +use function Safe\mkdir; use function sys_get_temp_dir; use function uniqid; diff --git a/test/unit/Util/CaptureErrorsTest.php b/test/unit/Util/CaptureErrorsTest.php deleted file mode 100644 index a1cddea9..00000000 --- a/test/unit/Util/CaptureErrorsTest.php +++ /dev/null @@ -1,38 +0,0 @@ -