Skip to content

Commit ab98cb0

Browse files
committed
Merge branch '5.x' into 5.next
# Conflicts: # src/Controller/ComposerController.php # src/ToolbarService.php # tests/TestCase/Mailer/Transport/DebugKitTransportTest.php
2 parents 3a1c0f7 + dc794a0 commit ab98cb0

28 files changed

Lines changed: 365 additions & 74 deletions

.github/SECURITY.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Security Policy
2+
3+
## Supported Versions
4+
5+
Security fixes are applied to all active versions listed in the
6+
[version map](https://github.com/cakephp/debug_kit/wiki#version-map).
7+
Versions marked as EOL no longer receive fixes.
8+
9+
## Reporting a Vulnerability
10+
11+
If you've found a security issue in CakePHP DebugKit, please use the following
12+
procedure instead of the normal bug reporting system. Instead of using the bug
13+
tracker, or one of the support forums please send an email to
14+
security [at] cakephp.org. Emails sent to this address go to the CakePHP core
15+
team on a private mailing list.
16+
17+
For each report, we try to first confirm the vulnerability. Once confirmed,
18+
the CakePHP team will take the following actions:
19+
20+
* Acknowledge to the reporter that we've received the issue, and are
21+
working on a fix. We ask that the reporter keep the issue confidential until we announce it.
22+
* Get a fix/patch prepared.
23+
* Prepare a post describing the vulnerability, and the possible exploits.
24+
* Release new versions of all affected versions.
25+
* Prominently feature the problem in the release announcement

.phive/phars.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<phive xmlns="https://phar.io/phive">
3-
<phar name="phpstan" version="2.1.31" installed="2.1.31" location="./tools/phpstan" copy="false"/>
4-
<phar name="psalm" version="7.0.0-beta16" installed="7.0.0-beta16" location="./tools/psalm" copy="false"/>
3+
<phar name="phpstan" version="2.1.55" installed="2.1.55" location="./tools/phpstan" copy="false"/>
4+
<phar name="psalm" version="7.0.0-beta19" installed="7.0.0-beta19" location="./tools/psalm" copy="false"/>
55
</phive>

phpstan-baseline.neon

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,5 @@
11
parameters:
22
ignoreErrors:
3-
-
4-
message: '#^Method DebugKit\\Mailer\\Transport\\DebugKitTransport\:\:send\(\) should return array\{headers\: string, message\: string\} but returns array\{headers\: non\-empty\-array\<string, string\>, message\: array\{text\: string, html\: string\}\}\.$#'
5-
identifier: return.type
6-
count: 1
7-
path: src/Mailer/Transport/DebugKitTransport.php
8-
93
-
104
message: '#^Parameter \#1 \$request of method DebugKit\\ToolbarService\:\:saveData\(\) expects Cake\\Http\\ServerRequest, Psr\\Http\\Message\\ServerRequestInterface given\.$#'
115
identifier: argument.type

psalm-baseline.xml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,6 @@
1111
</ImpureMethodCall>
1212
</file>
1313
<file src="src/Mailer/Transport/DebugKitTransport.php">
14-
<InvalidReturnStatement>
15-
<code><![CDATA[$result]]></code>
16-
</InvalidReturnStatement>
1714
<NullArgument>
1815
<code><![CDATA[$this->emailLog]]></code>
1916
</NullArgument>

src/Controller/ComposerController.php

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,22 +53,24 @@ public function checkDependencies(): void
5353

5454
$output = $this->executeComposerCommand($input);
5555
$dependencies = array_filter(explode("\n", $output->fetch()));
56-
$packages = [];
56+
$semverCompatible = [];
57+
$bcBreaks = [];
5758
foreach ($dependencies as $dependency) {
5859
if (str_contains($dependency, 'php_network_getaddresses')) {
5960
throw new RuntimeException('You have to be connected to the internet');
6061
}
6162
if (str_contains($dependency, '<highlight>')) {
62-
$packages['semverCompatible'][] = $dependency;
63+
$semverCompatible[] = $dependency;
6364
continue;
6465
}
65-
$packages['bcBreaks'][] = $dependency;
66+
$bcBreaks[] = $dependency;
6667
}
67-
if (!empty($packages['semverCompatible'])) {
68-
$packages['semverCompatible'] = trim(implode("\n", $packages['semverCompatible']));
68+
$packages = [];
69+
if ($semverCompatible) {
70+
$packages['semverCompatible'] = trim(implode("\n", $semverCompatible));
6971
}
70-
if (!empty($packages['bcBreaks'])) {
71-
$packages['bcBreaks'] = trim(implode("\n", $packages['bcBreaks']));
72+
if ($bcBreaks) {
73+
$packages['bcBreaks'] = trim(implode("\n", $bcBreaks));
7274
}
7375

7476
$this->viewBuilder()->setOption('serialize', ['packages']);

src/Controller/ToolbarController.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ public function clearCache(): void
4646
if (!$name) {
4747
throw new NotFoundException('Invalid cache engine name.');
4848
}
49+
if (!Cache::getConfig($name)) {
50+
throw new NotFoundException(sprintf('Unknown cache engine "%s".', $name));
51+
}
4952
$success = Cache::clear($name);
5053
$message = $success ?
5154
sprintf('%s cache cleared.', $name) :

src/Mailer/Transport/DebugKitTransport.php

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Cake\Core\App;
88
use Cake\Mailer\AbstractTransport;
99
use Cake\Mailer\Message;
10+
use InvalidArgumentException;
1011

1112
/**
1213
* Debug Transport class, useful for emulating the email sending process and inspecting
@@ -33,6 +34,11 @@ class DebugKitTransport extends AbstractTransport
3334
*/
3435
public function __construct(array $config = [], ?AbstractTransport $originalTransport = null)
3536
{
37+
if (!isset($config['debugKitLog']) || !$config['debugKitLog'] instanceof ArrayObject) {
38+
throw new InvalidArgumentException(
39+
'DebugKitTransport requires a `debugKitLog` config entry of type `ArrayObject`.',
40+
);
41+
}
3642
$this->emailLog = $config['debugKitLog'];
3743

3844
if ($originalTransport instanceof AbstractTransport) {
@@ -58,7 +64,17 @@ public function __construct(array $config = [], ?AbstractTransport $originalTran
5864
}
5965

6066
/**
61-
* @inheritDoc
67+
* Capture the message into the in-memory email log and optionally forward
68+
* to a wrapped real transport.
69+
*
70+
* Overrides the parent return shape: DebugKit stores the headers as an
71+
* associative array (so the panel can render rows) and splits the body
72+
* into text/html parts. Callers that consume this transport's return
73+
* value directly must account for this richer shape.
74+
*
75+
* @param \Cake\Mailer\Message $message The message to capture.
76+
* @return array
77+
* @phpstan-return array{headers: array<string, string>, message: array{text: string, html: string}}|array<string, mixed>
6278
*/
6379
public function send(Message $message): array
6480
{

src/Panel/RequestPanel.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public function shutdown(EventInterface $event): void
5454
'query' => Debugger::exportVarAsNodes($request->getQueryParams(), $maxDepth),
5555
'data' => Debugger::exportVarAsNodes($request->getData(), $maxDepth),
5656
'cookie' => Debugger::exportVarAsNodes($request->getCookieParams(), $maxDepth),
57-
'get' => Debugger::exportVarAsNodes($_GET, $maxDepth),
57+
'get' => Debugger::exportVarAsNodes($request->getQueryParams(), $maxDepth),
5858
'session' => Debugger::exportVarAsNodes($request->getSession()->read(), $maxDepth),
5959
'matchedRoute' => $request->getParam('_matchedRoute'),
6060
'headers' => [

src/ToolbarService.php

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -286,33 +286,40 @@ public function saveData(ServerRequest $request, ResponseInterface $response): R
286286

287287
foreach ($this->registry->loaded() as $name) {
288288
$panel = $this->registry->{$name};
289+
$data = null;
290+
$handlerInstalled = false;
289291
try {
290292
$data = $panel->data();
291293

292-
// Set error handler to catch warnings/errors during serialization
293-
set_error_handler(function ($errno, $errstr) use ($name): void {
294-
throw new Exception(sprintf("Serialization error in panel '%s': %s", $name, $errstr));
295-
});
294+
// Catch only warnings/notices raised during serialization; fatals
295+
// and exceptions in __sleep/__serialize already surface as throws.
296+
set_error_handler(
297+
function ($errno, $errstr) use ($name): bool {
298+
throw new Exception("Serialization error in panel '{$name}': {$errstr}");
299+
},
300+
E_WARNING | E_NOTICE | E_USER_WARNING | E_USER_NOTICE,
301+
);
302+
$handlerInstalled = true;
296303

297304
$content = serialize($data);
298-
299-
restore_error_handler();
300305
} catch (Exception $e) {
301-
restore_error_handler();
302-
303306
$errorMessage = sprintf(
304307
'Failed to serialize data for panel "%s": %s',
305308
$name,
306309
$e->getMessage(),
307310
);
308311

309312
Log::warning($errorMessage);
310-
Log::debug('Panel data type: ' . gettype($data ?? null));
313+
Log::debug('Panel data type: ' . gettype($data));
311314

312315
$content = serialize([
313316
'error' => $errorMessage,
314317
'panel' => $name,
315318
]);
319+
} finally {
320+
if ($handlerInstalled) {
321+
restore_error_handler();
322+
}
316323
}
317324
$row->panels[] = $requests->Panels->newEntity([
318325
'panel' => $name,

src/View/Helper/CredentialsHelper.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public function filter(mixed $in): mixed
5757
$link = $this->Html->tag('a', '******', [
5858
'class' => 'filtered-credentials',
5959
'title' => h($credentials),
60-
'onclick' => 'this.innerHTML = this.title',
60+
'onclick' => 'this.textContent = this.title',
6161
]);
6262

6363
return h($protocol) . $link . '@' . h($tail);

0 commit comments

Comments
 (0)