Skip to content

Commit 1cce5f3

Browse files
Merge branch '8.5' into 9.6
* 8.5: 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 492ee10 + 3141742 commit 1cce5f3

File tree

5 files changed

+67
-10
lines changed

5 files changed

+67
-10
lines changed

ChangeLog-9.6.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 9.6 release series are documented in this file using the [Keep a CHANGELOG](https://keepachangelog.com/) principles.
44

5+
## [9.6.33] - 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
## [9.6.32] - 2026-01-24
612

713
### Changed
@@ -218,6 +224,7 @@ All notable changes of the PHPUnit 9.6 release series are documented in this fil
218224
* [#5064](https://github.com/sebastianbergmann/phpunit/issues/5064): Deprecate `PHPUnit\Framework\TestCase::getMockClass()`
219225
* [#5132](https://github.com/sebastianbergmann/phpunit/issues/5132): Deprecate `Test` suffix for abstract test case classes
220226

227+
[9.6.33]: https://github.com/sebastianbergmann/phpunit/compare/9.6.32...9.6
221228
[9.6.32]: https://github.com/sebastianbergmann/phpunit/compare/9.6.31...9.6.32
222229
[9.6.31]: https://github.com/sebastianbergmann/phpunit/compare/9.6.30...9.6.31
223230
[9.6.30]: https://github.com/sebastianbergmann/phpunit/compare/9.6.29...9.6.30

src/Runner/PhptTestCase.php

Lines changed: 40 additions & 10 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;
@@ -89,17 +90,13 @@ final class PhptTestCase implements Reorderable, SelfDescribing, Test
8990
*/
9091
public function __construct(string $filename, ?AbstractPhpProcess $phpUtil = null)
9192
{
92-
if (!is_file($filename)) {
93-
throw new Exception(
94-
sprintf(
95-
'File "%s" does not exist.',
96-
$filename,
97-
),
98-
);
99-
}
93+
$this->ensureFileExists($filename);
10094

10195
$this->filename = $filename;
102-
$this->phpUtil = $phpUtil ?: AbstractPhpProcess::factory();
96+
97+
$this->ensureCoverageFileDoesNotExist();
98+
99+
$this->phpUtil = $phpUtil ?: AbstractPhpProcess::factory();
103100
}
104101

105102
/**
@@ -657,7 +654,7 @@ private function cleanupForCoverage(): RawCodeCoverageData
657654
$buffer = @file_get_contents($files['coverage']);
658655

659656
if ($buffer !== false) {
660-
$coverage = @unserialize($buffer);
657+
$coverage = @unserialize($buffer, ['allowed_classes' => false]);
661658

662659
if ($coverage === false) {
663660
$coverage = RawCodeCoverageData::fromXdebugWithoutPathCoverage([]);
@@ -862,4 +859,37 @@ private function settings(bool $collectCoverage): array
862859

863860
return $settings;
864861
}
862+
863+
/**
864+
* @throws Exception
865+
*/
866+
private function ensureFileExists(string $filename): void
867+
{
868+
if (!is_file($filename)) {
869+
throw new Exception(
870+
sprintf(
871+
'File "%s" does not exist.',
872+
$filename,
873+
),
874+
);
875+
}
876+
}
877+
878+
/**
879+
* @throws Exception
880+
*/
881+
private function ensureCoverageFileDoesNotExist(): void
882+
{
883+
$files = $this->getCoverageFiles();
884+
885+
if (file_exists($files['coverage'])) {
886+
throw new Exception(
887+
sprintf(
888+
'File %s exists, PHPT test %s will not be executed',
889+
$files['coverage'],
890+
$this->filename,
891+
),
892+
);
893+
}
894+
}
865895
}

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: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
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+
PHPUnit\TextUI\Command::main();
12+
--EXPECTF--
13+
Fatal error: Uncaught PHPUnit\Runner\Exception: File %stest.coverage exists, PHPT test %stest.phpt will not be executed%A

0 commit comments

Comments
 (0)