Skip to content

Commit a8b932b

Browse files
Merge branch '9.6' into 10.5
* 9.6: Do not run PHPT test when its temporary file for code coverage information exists We do not need to unserialize() objects here Extract method Fix CS/WS issue
2 parents bd265b6 + 1cce5f3 commit a8b932b

File tree

6 files changed

+81
-2
lines changed

6 files changed

+81
-2
lines changed

ChangeLog-10.5.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
All notable changes of the PHPUnit 10.5 release series are documented in this file using the [Keep a CHANGELOG](https://keepachangelog.com/) principles.
44

5+
## [10.5.62] - 2026-MM-DD
6+
7+
### Changed
8+
9+
* To prevent Poisoned Pipeline Execution (PPE) attacks using prepared `.coverage` files in pull requests, a PHPT test will no longer be run if the temporary file for writing code coverage information already exists before the test runs
10+
511
## [10.5.61] - 2026-01-24
612

713
### Changed
@@ -515,6 +521,7 @@ All notable changes of the PHPUnit 10.5 release series are documented in this fi
515521

516522
* [#5563](https://github.com/sebastianbergmann/phpunit/issues/5563): `createMockForIntersectionOfInterfaces()` does not automatically register mock object for expectation verification
517523

524+
[10.5.62]: https://github.com/sebastianbergmann/phpunit/compare/10.5.61...10.5
518525
[10.5.61]: https://github.com/sebastianbergmann/phpunit/compare/10.5.60...10.5.61
519526
[10.5.60]: https://github.com/sebastianbergmann/phpunit/compare/10.5.59...10.5.60
520527
[10.5.59]: https://github.com/sebastianbergmann/phpunit/compare/10.5.58...10.5.59
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php declare(strict_types=1);
2+
/*
3+
* This file is part of PHPUnit.
4+
*
5+
* (c) Sebastian Bergmann <[email protected]>
6+
*
7+
* For the full copyright and license information, please view the LICENSE
8+
* file that was distributed with this source code.
9+
*/
10+
namespace PHPUnit\Runner;
11+
12+
use RuntimeException;
13+
14+
/**
15+
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
16+
*
17+
* @internal This class is not covered by the backward compatibility promise for PHPUnit
18+
*/
19+
final class CodeCoverageFileExistsException extends RuntimeException implements Exception
20+
{
21+
}

src/Runner/PhptTestCase.php

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use function explode;
2020
use function extension_loaded;
2121
use function file;
22+
use function file_exists;
2223
use function file_get_contents;
2324
use function file_put_contents;
2425
use function is_array;
@@ -31,6 +32,7 @@
3132
use function preg_split;
3233
use function realpath;
3334
use function rtrim;
35+
use function sprintf;
3436
use function str_contains;
3537
use function str_replace;
3638
use function str_starts_with;
@@ -89,7 +91,10 @@ final class PhptTestCase implements Reorderable, SelfDescribing, Test
8991
public function __construct(string $filename, ?AbstractPhpProcess $phpUtil = null)
9092
{
9193
$this->filename = $filename;
92-
$this->phpUtil = $phpUtil ?: AbstractPhpProcess::factory();
94+
95+
$this->ensureCoverageFileDoesNotExist();
96+
97+
$this->phpUtil = $phpUtil ?: AbstractPhpProcess::factory();
9398
}
9499

95100
/**
@@ -654,7 +659,7 @@ private function cleanupForCoverage(): RawCodeCoverageData
654659
}
655660

656661
if ($buffer !== false) {
657-
$coverage = @unserialize($buffer);
662+
$coverage = @unserialize($buffer, ['allowed_class' => false]);
658663

659664
if ($coverage === false) {
660665
$coverage = RawCodeCoverageData::fromXdebugWithoutPathCoverage([]);
@@ -840,4 +845,22 @@ private function settings(bool $collectCoverage): array
840845

841846
return $settings;
842847
}
848+
849+
/**
850+
* @throws CodeCoverageFileExistsException
851+
*/
852+
private function ensureCoverageFileDoesNotExist(): void
853+
{
854+
$files = $this->getCoverageFiles();
855+
856+
if (file_exists($files['coverage'])) {
857+
throw new CodeCoverageFileExistsException(
858+
sprintf(
859+
'File %s exists, PHPT test %s will not be executed',
860+
$files['coverage'],
861+
$this->filename,
862+
),
863+
);
864+
}
865+
}
843866
}

tests/end-to-end/_files/phpt-coverage-file-exists/test.coverage

Whitespace-only changes.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
--TEST--
2+
test
3+
--FILE--
4+
<?php declare(strict_types=1);
5+
print 'test';
6+
--EXPECT--
7+
test
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
--TEST--
2+
Error when code coverage file exists
3+
--FILE--
4+
<?php declare(strict_types=1);
5+
$_SERVER['argv'][] = '--do-not-cache-result';
6+
$_SERVER['argv'][] = '--no-configuration';
7+
$_SERVER['argv'][] = \realpath(__DIR__ . '/../_files/phpt-coverage-file-exists/test.phpt');
8+
9+
require_once __DIR__ . '/../../bootstrap.php';
10+
11+
(new PHPUnit\TextUI\Application)->run($_SERVER['argv']);
12+
--EXPECTF--
13+
PHPUnit %s by Sebastian Bergmann and contributors.
14+
15+
Runtime: %s
16+
17+
There was 1 PHPUnit test runner warning:
18+
19+
1) File %stest.coverage exists, PHPT test %stest.phpt will not be executed
20+
21+
No tests executed!

0 commit comments

Comments
 (0)