diff --git a/tests/data/claypit/c3.php b/tests/data/claypit/c3.php index 96720d95ad..78ce38f992 100644 --- a/tests/data/claypit/c3.php +++ b/tests/data/claypit/c3.php @@ -57,7 +57,13 @@ function __c3_error($message) // Load Codeception Config $config_file = realpath(__DIR__) . DIRECTORY_SEPARATOR . 'codeception.yml'; if (isset($_SERVER['HTTP_X_CODECEPTION_CODECOVERAGE_CONFIG'])) { - $config_file = realpath(__DIR__) . DIRECTORY_SEPARATOR . $_SERVER['HTTP_X_CODECEPTION_CODECOVERAGE_CONFIG']; + $config_name = basename($_SERVER['HTTP_X_CODECEPTION_CODECOVERAGE_CONFIG']); + // Only allow .yml files with safe characters + if (preg_match('/^[\w\-]+\.yml$/', $config_name)) { + $config_file = realpath(__DIR__) . DIRECTORY_SEPARATOR . $config_name; + } else { + __c3_error('Invalid config file name'); + } } if (!file_exists($config_file)) { __c3_error(sprintf("Codeception config file '%s' not found", $config_file)); @@ -140,12 +146,20 @@ function __c3_factory($filename) : new PHP_CodeCoverage(); - if (isset($_SERVER['HTTP_X_CODECEPTION_CODECOVERAGE_SUITE'])) { - $suite = $_SERVER['HTTP_X_CODECEPTION_CODECOVERAGE_SUITE']; - try { - $settings = \Codeception\Configuration::suiteSettings($suite, \Codeception\Configuration::config()); - } catch (Exception $e) { - __c3_error($e->getMessage()); + if (isset($_SERVER['HTTP_X_CODECEPTION_CODECOVERAGE_CONFIG'])) { + $config_name = basename($_SERVER['HTTP_X_CODECEPTION_CODECOVERAGE_CONFIG']); + if (preg_match('/^[\w\-]+\.yml$/', $config_name)) { + $config_dir = realpath(__DIR__); + $config_file = $config_dir . DIRECTORY_SEPARATOR . $config_name; + $real_config_file = realpath($config_file); + // Ensure the file is inside the config directory + if ($real_config_file && strpos($real_config_file, $config_dir . DIRECTORY_SEPARATOR) === 0) { + $config_file = $real_config_file; + } else { + __c3_error('Invalid config file path'); + } + } else { + __c3_error('Invalid config file name'); } } else { $settings = \Codeception\Configuration::config(); @@ -237,4 +251,4 @@ function () use ($codeCoverage, $current_report) { } } -// @codeCoverageIgnoreEnd \ No newline at end of file +// @codeCoverageIgnoreEnd diff --git a/tests/data/claypit/tests/_bootstrap.php b/tests/data/claypit/tests/_bootstrap.php index b376ddd542..5f397f9fe6 100644 --- a/tests/data/claypit/tests/_bootstrap.php +++ b/tests/data/claypit/tests/_bootstrap.php @@ -2,6 +2,16 @@ require_once __DIR__.'/_data/MyGroupHighlighter.php'; require_once __DIR__.'/_data/VerbosityLevelOutput.php'; -@unlink(\Codeception\Configuration::outputDir().'order.txt'); -$fh = fopen(\Codeception\Configuration::outputDir().'order.txt', 'a'); -fwrite($fh, 'B'); +$orderFile = \Codeception\Configuration::outputDir().'order.txt'; +if (file_exists($orderFile) && !unlink($orderFile)) { + throw new \RuntimeException("Failed to delete $orderFile"); +} + +$fh = fopen($orderFile, 'a'); +if ($fh === false) { + throw new \RuntimeException("Failed to open $orderFile for writing"); +} +if (fwrite($fh, 'B') === false) { + throw new \RuntimeException("Failed to write to $orderFile"); +} +fclose($fh); diff --git a/tests/unit/Codeception/Module/WebDriverTest.php b/tests/unit/Codeception/Module/WebDriverTest.php index 4799c78b79..a4da67b5fe 100644 --- a/tests/unit/Codeception/Module/WebDriverTest.php +++ b/tests/unit/Codeception/Module/WebDriverTest.php @@ -116,17 +116,35 @@ public function testSeeInPopup() public function testScreenshot() { + $outputDir = \Codeception\Configuration::outputDir(); + $safeDir = realpath($outputDir . 'debug') . DIRECTORY_SEPARATOR; + $testName = 'debugTest'; + $debugScreenshot = $safeDir . $testName . '.png'; + $testshot = $outputDir . 'testshot.png'; + $this->module->amOnPage('/'); - @unlink(\Codeception\Configuration::outputDir().'testshot.png'); - $testName="debugTest"; + + // Only delete if file is in the safe directory and name is valid + $realTestshot = realpath($testshot); + if ($realTestshot !== false && strpos($realTestshot, realpath($outputDir)) === 0 && preg_match('/^[\w\-]+\.png$/', basename($testshot))) { + @unlink($realTestshot); + } $this->module->makeScreenshot($testName); - $this->assertFileExists(\Codeception\Configuration::outputDir().'debug/'.$testName.'.png'); - @unlink(\Codeception\Configuration::outputDir().'debug/'.$testName.'.png'); + $this->assertFileExists($debugScreenshot); - $this->module->_saveScreenshot(\Codeception\Configuration::outputDir().'testshot.png'); - $this->assertFileExists(\Codeception\Configuration::outputDir().'testshot.png'); - @unlink(\Codeception\Configuration::outputDir().'testshot.png'); + $realDebugScreenshot = realpath($debugScreenshot); + if ($realDebugScreenshot !== false && strpos($realDebugScreenshot, $safeDir) === 0 && preg_match('/^[\w\-]+\.png$/', $testName . '.png')) { + @unlink($realDebugScreenshot); + } + + $this->module->_saveScreenshot($testshot); + $this->assertFileExists($testshot); + + $realTestshot = realpath($testshot); + if ($realTestshot !== false && strpos($realTestshot, realpath($outputDir)) === 0 && preg_match('/^[\w\-]+\.png$/', basename($testshot))) { + @unlink($realTestshot); + } } public function testSubmitForm() { diff --git a/tests/unit/Codeception/ParserTest.php b/tests/unit/Codeception/ParserTest.php index 8639ae2a1a..f8b168bd3b 100644 --- a/tests/unit/Codeception/ParserTest.php +++ b/tests/unit/Codeception/ParserTest.php @@ -122,7 +122,16 @@ public function testSteps() public function testStepsWithFriends() { - $code = file_get_contents(\Codeception\Configuration::projectDir().'tests/web/FriendsCept.php'); + // Only allow reading files from a known directory + $allowedFiles = [ + \Codeception\Configuration::projectDir().'tests/cli/UnitCept.php', + ]; + + $filePath = \Codeception\Configuration::projectDir().'tests/cli/UnitCept.php'; + if (!in_array($filePath, $allowedFiles, true)) { + throw new \RuntimeException('Invalid file path'); + } + $code = file_get_contents($filePath); $this->assertContains('$I->haveFriend', $code); $this->parser->parseSteps($code); $text = $this->scenario->getText(); @@ -155,4 +164,4 @@ public function testParseFileWhichUnsetsFileVariable() $classes = Parser::getClassesFromFile(codecept_data_dir('unsetFile.php')); $this->assertEquals([], $classes); } -} \ No newline at end of file +}