diff --git a/lib/private/OpenMetrics/Exporters/AppsInfo.php b/lib/private/OpenMetrics/Exporters/AppsInfo.php index 33597795e7d51..0910007c10a58 100644 --- a/lib/private/OpenMetrics/Exporters/AppsInfo.php +++ b/lib/private/OpenMetrics/Exporters/AppsInfo.php @@ -47,10 +47,10 @@ public function help(): string { #[Override] public function metrics(): Generator { - yield new Metric( - 1, - $this->appManager->getAppInstalledVersions(true), - time() - ); + $apps = []; + foreach ($this->appManager->getAppInstalledVersions(true) as $appId => $version) { + $apps[str_replace('-', '_', $appId)] = $version; + } + yield new Metric(1, $apps, time()); } } diff --git a/lib/public/OpenMetrics/Metric.php b/lib/public/OpenMetrics/Metric.php index 47e925b01b75f..b5deb324db41f 100644 --- a/lib/public/OpenMetrics/Metric.php +++ b/lib/public/OpenMetrics/Metric.php @@ -19,9 +19,18 @@ public function __construct( public array $labels = [], public int|float|null $timestamp = null, ) { + $this->validateLabels(); } public function label(string $name): ?string { return $this->labels[$name] ?? null; } + + private function validateLabels(): void { + foreach ($this->labels as $label => $_value) { + if (preg_match('/^[a-zA-Z_][a-zA-Z0-9_]*$/', (string)$label) !== 1) { + throw new \InvalidArgumentException('Invalid OpenMetrics label name: "' . $label . '"'); + } + } + } } diff --git a/tests/Core/Controller/OpenMetricsControllerTest.php b/tests/Core/Controller/OpenMetricsControllerTest.php index fdc81ad5d2c0e..7832afeb40092 100644 --- a/tests/Core/Controller/OpenMetricsControllerTest.php +++ b/tests/Core/Controller/OpenMetricsControllerTest.php @@ -87,6 +87,17 @@ public function testGetMetrics(): void { $this->assertStringMatchesFormat($expected, $fullOutput); } + public function testMetricRejectsInvalidLabelNames(): void { + $this->expectException(\InvalidArgumentException::class); + new Metric(1, ['hide-photos' => '1.0.0']); + } + + public function testMetricAcceptsValidLabelNames(): void { + $metric = new Metric(1, ['hide_photos' => '1.0.0', 'normal_app' => '2.0.0']); + $this->assertEquals('1.0.0', $metric->label('hide_photos')); + $this->assertEquals('2.0.0', $metric->label('normal_app')); + } + public function testGetMetricsFromForbiddenIp(): void { $this->config->expects($this->once()) ->method('getSystemValue')