From 02a8f472e1c559db9bcbc401b926ad4a2a57d1ed Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Mon, 28 Sep 2026 09:49:22 +0200 Subject: [PATCH] fix(adminaudit): Allow named placeholders via CriticalActionPerformedEvent Assisted-by: ClaudeCode:claude-opus-5.5 Signed-off-by: Joas Schilling --- apps/admin_audit/lib/Actions/Action.php | 7 ++- ...iticalActionPerformedEventListenerTest.php | 50 +++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 apps/admin_audit/tests/Listener/CriticalActionPerformedEventListenerTest.php diff --git a/apps/admin_audit/lib/Actions/Action.php b/apps/admin_audit/lib/Actions/Action.php index 29988b44c5441..7d41eff4df6e4 100644 --- a/apps/admin_audit/lib/Actions/Action.php +++ b/apps/admin_audit/lib/Actions/Action.php @@ -47,17 +47,22 @@ public function log( } $replaceArray = []; + $context = ['app' => 'admin_audit']; foreach ($elements as $element) { $value = $params[$element]; if ($value instanceof \DateTimeInterface) { $value = $value->format('Y-m-d H:i:s'); } $replaceArray[] = $value; + // Named {placeholders} are interpolated by the logger + if (str_contains($text, '{' . $element . '}')) { + $context[$element] = $value; + } } $this->logger->info( vsprintf($text, $replaceArray), - ['app' => 'admin_audit'], + $context, ); } } diff --git a/apps/admin_audit/tests/Listener/CriticalActionPerformedEventListenerTest.php b/apps/admin_audit/tests/Listener/CriticalActionPerformedEventListenerTest.php new file mode 100644 index 0000000000000..7279a0aec25d5 --- /dev/null +++ b/apps/admin_audit/tests/Listener/CriticalActionPerformedEventListenerTest.php @@ -0,0 +1,50 @@ +logger = $this->createMock(AuditLogger::class); + $this->listener = new CriticalActionPerformedEventListener($this->logger); + } + + public function testSprintfPlaceholders(): void { + $this->logger->expects($this->once()) + ->method('info') + ->with('Share "42" was accepted by "alice"', ['app' => 'admin_audit']); + + $this->listener->handle(new CriticalActionPerformedEvent('Share "%s" was accepted by "%s"', ['42', 'alice'])); + } + + public function testNamedPlaceholders(): void { + $this->logger->expects($this->once()) + ->method('info') + ->with( + 'Bruteforce attempt from "{ip}" detected for action "{action}" not throttled due to allow-list.', + ['app' => 'admin_audit', 'ip' => '10.0.0.1', 'action' => 'login'], + ); + + $this->listener->handle(new CriticalActionPerformedEvent( + 'Bruteforce attempt from "{ip}" detected for action "{action}" not throttled due to allow-list.', + ['ip' => '10.0.0.1', 'action' => 'login'], + )); + } +}