From 946f94c0eb702ea8530d9f7f321aac7cd95a96c0 Mon Sep 17 00:00:00 2001 From: Josh Date: Mon, 27 Jul 2026 17:27:09 -0400 Subject: [PATCH 1/3] fix(taskprocessing): return on malformed AppAPI webhook method Signed-off-by: Josh --- lib/private/TaskProcessing/Manager.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/private/TaskProcessing/Manager.php b/lib/private/TaskProcessing/Manager.php index 27c5bac611416..4d35b8a5264ef 100644 --- a/lib/private/TaskProcessing/Manager.php +++ b/lib/private/TaskProcessing/Manager.php @@ -1923,11 +1923,9 @@ public function cleanupTaskProcessingTaskFiles(int $ageInSeconds = self::MAX_TAS private function runWebhook(Task $task): void { $uri = $task->getWebhookUri(); $method = $task->getWebhookMethod(); - if (!$uri || !$method) { return; } - if (in_array($method, ['HTTP:GET', 'HTTP:POST', 'HTTP:PUT', 'HTTP:DELETE'], true)) { $client = $this->clientService->newClient(); $httpMethod = preg_replace('/^HTTP:/', '', $method); @@ -1947,8 +1945,13 @@ private function runWebhook(Task $task): void { } } elseif (str_starts_with($method, 'AppAPI:') && str_starts_with($uri, '/')) { $parsedMethod = explode(':', $method, 4); - if (count($parsedMethod) < 3) { + if ( + count($parsedMethod) !== 3 + || $parsedMethod[1] === '' + || !in_array($parsedMethod[2], ['GET', 'POST', 'PUT', 'DELETE'], true) + ) { $this->logger->warning('Task processing AppAPI webhook failed for task ' . $task->getId() . '. Invalid method: ' . $method); + return; } [, $exAppId, $httpMethod] = $parsedMethod; if (!$this->appManager->isEnabledForAnyone('app_api')) { From ac1fd94353ac61f29237fd40d33785935e3c1d27 Mon Sep 17 00:00:00 2001 From: Josh Date: Mon, 27 Jul 2026 17:37:26 -0400 Subject: [PATCH 2/3] fix(taskprocessing): pass AppAPI webhook errors as logger context Signed-off-by: Josh --- lib/private/TaskProcessing/Manager.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/private/TaskProcessing/Manager.php b/lib/private/TaskProcessing/Manager.php index 4d35b8a5264ef..a78b24235743b 100644 --- a/lib/private/TaskProcessing/Manager.php +++ b/lib/private/TaskProcessing/Manager.php @@ -1978,10 +1978,14 @@ private function runWebhook(Task $task): void { $requestOptions = [ 'timeout' => 30, ]; - $response = $appApiFunctions->exAppRequest($exAppId, $uri, $task->getUserId(), $httpMethod, $requestParams, $requestOptions); - if (is_array($response) && isset($response['error'])) { - $this->logger->warning('Task processing AppAPI webhook failed for task ' . $task->getId() . '. Error during request to ExApp(' . $exAppId . '): ', $response['error']); - } + try { + $response = $appApiFunctions->exAppRequest($exAppId, $uri, $task->getUserId(), $httpMethod, $requestParams, $requestOptions); + if (is_array($response) && isset($response['error'])) { + $this->logger->warning('Task processing AppAPI webhook failed for task ' . $task->getId() . '. Error during request to ExApp(' . $exAppId . ').', ['error' => $response['error']]); + } + } catch (\Throwable $e) { + $this->logger->warning('Task processing AppAPI webhook failed for task ' . $task->getId() . '. Request failed.', ['exception' => $e]); + } } } } From c6202ce0dbcf55301c59681ab291e23706036b54 Mon Sep 17 00:00:00 2001 From: Josh Date: Mon, 27 Jul 2026 17:44:43 -0400 Subject: [PATCH 3/3] chore: tidy up runWebhook formatting pure refactor: whitespace, line wrapping, logger formatting, early return/minimize some nesting Signed-off-by: Josh --- lib/private/TaskProcessing/Manager.php | 154 ++++++++++++++++++------- 1 file changed, 110 insertions(+), 44 deletions(-) diff --git a/lib/private/TaskProcessing/Manager.php b/lib/private/TaskProcessing/Manager.php index a78b24235743b..39ff4bed46cb8 100644 --- a/lib/private/TaskProcessing/Manager.php +++ b/lib/private/TaskProcessing/Manager.php @@ -1923,9 +1923,11 @@ public function cleanupTaskProcessingTaskFiles(int $ageInSeconds = self::MAX_TAS private function runWebhook(Task $task): void { $uri = $task->getWebhookUri(); $method = $task->getWebhookMethod(); + if (!$uri || !$method) { return; } + if (in_array($method, ['HTTP:GET', 'HTTP:POST', 'HTTP:PUT', 'HTTP:DELETE'], true)) { $client = $this->clientService->newClient(); $httpMethod = preg_replace('/^HTTP:/', '', $method); @@ -1936,56 +1938,120 @@ private function runWebhook(Task $task): void { ]), 'headers' => ['Content-Type' => 'application/json'], ]; + try { $client->request($httpMethod, $uri, $options); } catch (ClientException|ServerException $e) { - $this->logger->warning('Task processing HTTP webhook failed for task ' . $task->getId() . '. Request failed', ['exception' => $e]); + $this->logger->warning( + 'Task processing HTTP webhook failed for task ' . $task->getId() . '. Request failed', + ['exception' => $e], + ); } catch (\Exception|\Throwable $e) { - $this->logger->warning('Task processing HTTP webhook failed for task ' . $task->getId() . '. Unknown error', ['exception' => $e]); + $this->logger->warning( + 'Task processing HTTP webhook failed for task ' . $task->getId() . '. Unknown error', + ['exception' => $e], + ); } - } elseif (str_starts_with($method, 'AppAPI:') && str_starts_with($uri, '/')) { - $parsedMethod = explode(':', $method, 4); - if ( - count($parsedMethod) !== 3 - || $parsedMethod[1] === '' - || !in_array($parsedMethod[2], ['GET', 'POST', 'PUT', 'DELETE'], true) - ) { - $this->logger->warning('Task processing AppAPI webhook failed for task ' . $task->getId() . '. Invalid method: ' . $method); - return; - } - [, $exAppId, $httpMethod] = $parsedMethod; - if (!$this->appManager->isEnabledForAnyone('app_api')) { - $this->logger->warning('Task processing AppAPI webhook failed for task ' . $task->getId() . '. AppAPI is disabled or not installed.'); - return; - } - try { - $appApiFunctions = Server::get(PublicFunctions::class); - } catch (ContainerExceptionInterface|NotFoundExceptionInterface) { - $this->logger->warning('Task processing AppAPI webhook failed for task ' . $task->getId() . '. Could not get AppAPI public functions.'); - return; - } - $exApp = $appApiFunctions->getExApp($exAppId); - if ($exApp === null) { - $this->logger->warning('Task processing AppAPI webhook failed for task ' . $task->getId() . '. ExApp ' . $exAppId . ' is missing.'); - return; - } elseif (!$exApp['enabled']) { - $this->logger->warning('Task processing AppAPI webhook failed for task ' . $task->getId() . '. ExApp ' . $exAppId . ' is disabled.'); - return; + + return; + } + + if (!str_starts_with($method, 'AppAPI:') || !str_starts_with($uri, '/')) { + return; + } + + $parsedMethod = explode(':', $method, 4); + if ( + count($parsedMethod) !== 3 + || $parsedMethod[1] === '' + || !in_array($parsedMethod[2], ['GET', 'POST', 'PUT', 'DELETE'], true) + ) { + $this->logger->warning( + 'Task processing AppAPI webhook failed for task ' + . $task->getId() + . '. Invalid method: ' + . $method, + ); + return; + } + + [, $exAppId, $httpMethod] = $parsedMethod; + + if (!$this->appManager->isEnabledForAnyone('app_api')) { + $this->logger->warning( + 'Task processing AppAPI webhook failed for task ' + . $task->getId() + . '. AppAPI is disabled or not installed.', + ); + return; + } + + try { + $appApiFunctions = Server::get(PublicFunctions::class); + } catch (ContainerExceptionInterface|NotFoundExceptionInterface) { + $this->logger->warning( + 'Task processing AppAPI webhook failed for task ' + . $task->getId() + . '. Could not get AppAPI public functions.', + ); + return; + } + + $exApp = $appApiFunctions->getExApp($exAppId); + if ($exApp === null) { + $this->logger->warning( + 'Task processing AppAPI webhook failed for task ' + . $task->getId() + . '. ExApp ' + . $exAppId + . ' is missing.', + ); + return; + } + + if (!$exApp['enabled']) { + $this->logger->warning( + 'Task processing AppAPI webhook failed for task ' + . $task->getId() + . '. ExApp ' + . $exAppId + . ' is disabled.', + ); + return; + } + + $requestParams = [ + 'task' => $task->jsonSerialize(), + ]; + $requestOptions = [ + 'timeout' => 30, + ]; + + try { + $response = $appApiFunctions->exAppRequest( + $exAppId, + $uri, + $task->getUserId(), + $httpMethod, + $requestParams, + $requestOptions, + ); + + if (is_array($response) && isset($response['error'])) { + $this->logger->warning( + 'Task processing AppAPI webhook failed for task ' + . $task->getId() + . '. Error during request to ExApp(' + . $exAppId + . ').', + ['error' => $response['error']], + ); } - $requestParams = [ - 'task' => $task->jsonSerialize(), - ]; - $requestOptions = [ - 'timeout' => 30, - ]; - try { - $response = $appApiFunctions->exAppRequest($exAppId, $uri, $task->getUserId(), $httpMethod, $requestParams, $requestOptions); - if (is_array($response) && isset($response['error'])) { - $this->logger->warning('Task processing AppAPI webhook failed for task ' . $task->getId() . '. Error during request to ExApp(' . $exAppId . ').', ['error' => $response['error']]); - } - } catch (\Throwable $e) { - $this->logger->warning('Task processing AppAPI webhook failed for task ' . $task->getId() . '. Request failed.', ['exception' => $e]); - } + } catch (\Throwable $e) { + $this->logger->warning( + 'Task processing AppAPI webhook failed for task ' . $task->getId() . '. Request failed.', + ['exception' => $e], + ); } } }