From 0ec3e363ee3b8f6536ac163ea40e0b7da8cee87b Mon Sep 17 00:00:00 2001 From: Vault Automation Date: Wed, 29 Apr 2026 08:10:39 -0600 Subject: [PATCH] Vault-44369 return keys regardless of value inside billing endpoint (#14286) (#14371) * create the metrics inside the response even if the value is zero * tests * fix a test Co-authored-by: Amir Aslamov --- vault/logical_system_use_case_billing.go | 196 ++++++++---------- vault/logical_system_use_case_billing_test.go | 195 ++++++++++++++++- 2 files changed, 275 insertions(+), 116 deletions(-) diff --git a/vault/logical_system_use_case_billing.go b/vault/logical_system_use_case_billing.go index 0c8c1af6d7..428a3ce250 100644 --- a/vault/logical_system_use_case_billing.go +++ b/vault/logical_system_use_case_billing.go @@ -151,9 +151,8 @@ func (b *SystemBackend) buildMonthBillingData(ctx context.Context, month time.Ti // Build the usage metrics usageMetrics := []map[string]interface{}{} - kvDetails := []map[string]interface{}{} - if combinedKvCounts > 0 { - kvDetails = append(kvDetails, map[string]interface{}{"type": "kv", "count": combinedKvCounts}) + kvDetails := []map[string]interface{}{ + {"type": "kv", "count": combinedKvCounts}, } usageMetrics = append(usageMetrics, map[string]interface{}{ "metric_name": "static_secrets", @@ -181,15 +180,10 @@ func (b *SystemBackend) buildMonthBillingData(ctx context.Context, month time.Ti }, }) - dataProtectionDetails := []map[string]interface{}{} - if transitCounts > 0 { - dataProtectionDetails = append(dataProtectionDetails, map[string]interface{}{"type": "transit", "count": transitCounts}) - } - if transformCounts > 0 { - dataProtectionDetails = append(dataProtectionDetails, map[string]interface{}{"type": "transform", "count": transformCounts}) - } - if gcpKmsCounts > 0 { - dataProtectionDetails = append(dataProtectionDetails, map[string]interface{}{"type": "gcpkms", "count": gcpKmsCounts}) + dataProtectionDetails := []map[string]interface{}{ + {"type": "transit", "count": transitCounts}, + {"type": "transform", "count": transformCounts}, + {"type": "gcpkms", "count": gcpKmsCounts}, } usageMetrics = append(usageMetrics, map[string]interface{}{ @@ -206,12 +200,9 @@ func (b *SystemBackend) buildMonthBillingData(ctx context.Context, month time.Ti } usageMetrics = append(usageMetrics, pkiMetric) - managedKeysDetails := []map[string]interface{}{} - if combinedManagedKeyCounts.TotpKeys > 0 { - managedKeysDetails = append(managedKeysDetails, map[string]interface{}{"type": "totp", "count": combinedManagedKeyCounts.TotpKeys}) - } - if combinedManagedKeyCounts.KmseKeys > 0 { - managedKeysDetails = append(managedKeysDetails, map[string]interface{}{"type": "kmse", "count": combinedManagedKeyCounts.KmseKeys}) + managedKeysDetails := []map[string]interface{}{ + {"type": "totp", "count": combinedManagedKeyCounts.TotpKeys}, + {"type": "kmse", "count": combinedManagedKeyCounts.KmseKeys}, } usageMetrics = append(usageMetrics, map[string]interface{}{ "metric_name": "managed_keys", @@ -281,63 +272,54 @@ func (c *Core) computeUpdatedAt(ctx context.Context, month, currentMonth time.Ti // buildDynamicRolesMetric creates the dynamic_roles metric from role counts. func buildDynamicRolesMetric(counts *RoleCounts) map[string]interface{} { total := 0 + awsCount := 0 + azureCount := 0 + databaseCount := 0 + gcpCount := 0 + ldapCount := 0 + openldapCount := 0 + alicloudCount := 0 + rabbitmqCount := 0 + consulCount := 0 + nomadCount := 0 + kubernetesCount := 0 + mongodbatlasCount := 0 + terraformCount := 0 + if counts != nil { - total = counts.AWSDynamicRoles + - counts.AzureDynamicRoles + - counts.DatabaseDynamicRoles + - counts.GCPRolesets + - counts.LDAPDynamicRoles + - counts.OpenLDAPDynamicRoles + - counts.AlicloudDynamicRoles + - counts.RabbitMQDynamicRoles + - counts.ConsulDynamicRoles + - counts.NomadDynamicRoles + - counts.KubernetesDynamicRoles + - counts.MongoDBAtlasDynamicRoles + - counts.TerraformCloudDynamicRoles + awsCount = counts.AWSDynamicRoles + azureCount = counts.AzureDynamicRoles + databaseCount = counts.DatabaseDynamicRoles + gcpCount = counts.GCPRolesets + ldapCount = counts.LDAPDynamicRoles + openldapCount = counts.OpenLDAPDynamicRoles + alicloudCount = counts.AlicloudDynamicRoles + rabbitmqCount = counts.RabbitMQDynamicRoles + consulCount = counts.ConsulDynamicRoles + nomadCount = counts.NomadDynamicRoles + kubernetesCount = counts.KubernetesDynamicRoles + mongodbatlasCount = counts.MongoDBAtlasDynamicRoles + terraformCount = counts.TerraformCloudDynamicRoles + + total = awsCount + azureCount + databaseCount + gcpCount + ldapCount + + openldapCount + alicloudCount + rabbitmqCount + consulCount + + nomadCount + kubernetesCount + mongodbatlasCount + terraformCount } - details := []map[string]interface{}{} - if counts != nil { - if counts.AWSDynamicRoles > 0 { - details = append(details, map[string]interface{}{"type": "aws_dynamic", "count": counts.AWSDynamicRoles}) - } - if counts.AzureDynamicRoles > 0 { - details = append(details, map[string]interface{}{"type": "azure_dynamic", "count": counts.AzureDynamicRoles}) - } - if counts.DatabaseDynamicRoles > 0 { - details = append(details, map[string]interface{}{"type": "database_dynamic", "count": counts.DatabaseDynamicRoles}) - } - if counts.GCPRolesets > 0 { - details = append(details, map[string]interface{}{"type": "gcp_dynamic", "count": counts.GCPRolesets}) - } - if counts.LDAPDynamicRoles > 0 { - details = append(details, map[string]interface{}{"type": "ldap_dynamic", "count": counts.LDAPDynamicRoles}) - } - if counts.OpenLDAPDynamicRoles > 0 { - details = append(details, map[string]interface{}{"type": "openldap_dynamic", "count": counts.OpenLDAPDynamicRoles}) - } - if counts.AlicloudDynamicRoles > 0 { - details = append(details, map[string]interface{}{"type": "alicloud_dynamic", "count": counts.AlicloudDynamicRoles}) - } - if counts.RabbitMQDynamicRoles > 0 { - details = append(details, map[string]interface{}{"type": "rabbitmq_dynamic", "count": counts.RabbitMQDynamicRoles}) - } - if counts.ConsulDynamicRoles > 0 { - details = append(details, map[string]interface{}{"type": "consul_dynamic", "count": counts.ConsulDynamicRoles}) - } - if counts.NomadDynamicRoles > 0 { - details = append(details, map[string]interface{}{"type": "nomad_dynamic", "count": counts.NomadDynamicRoles}) - } - if counts.KubernetesDynamicRoles > 0 { - details = append(details, map[string]interface{}{"type": "kubernetes_dynamic", "count": counts.KubernetesDynamicRoles}) - } - if counts.MongoDBAtlasDynamicRoles > 0 { - details = append(details, map[string]interface{}{"type": "mongodbatlas_dynamic", "count": counts.MongoDBAtlasDynamicRoles}) - } - if counts.TerraformCloudDynamicRoles > 0 { - details = append(details, map[string]interface{}{"type": "terraform_dynamic", "count": counts.TerraformCloudDynamicRoles}) - } + details := []map[string]interface{}{ + {"type": "aws_dynamic", "count": awsCount}, + {"type": "azure_dynamic", "count": azureCount}, + {"type": "database_dynamic", "count": databaseCount}, + {"type": "gcp_dynamic", "count": gcpCount}, + {"type": "ldap_dynamic", "count": ldapCount}, + {"type": "openldap_dynamic", "count": openldapCount}, + {"type": "alicloud_dynamic", "count": alicloudCount}, + {"type": "rabbitmq_dynamic", "count": rabbitmqCount}, + {"type": "consul_dynamic", "count": consulCount}, + {"type": "nomad_dynamic", "count": nomadCount}, + {"type": "kubernetes_dynamic", "count": kubernetesCount}, + {"type": "mongodbatlas_dynamic", "count": mongodbatlasCount}, + {"type": "terraform_dynamic", "count": terraformCount}, } return map[string]interface{}{ @@ -352,39 +334,35 @@ func buildDynamicRolesMetric(counts *RoleCounts) map[string]interface{} { // buildAutoRotatedRolesMetric creates the auto_rotated_roles metric from role counts. func buildAutoRotatedRolesMetric(counts *RoleCounts) map[string]interface{} { total := 0 + awsCount := 0 + azureCount := 0 + databaseCount := 0 + gcpStaticCount := 0 + gcpImpersonatedCount := 0 + ldapCount := 0 + openldapCount := 0 + if counts != nil { - total = counts.AWSStaticRoles + - counts.AzureStaticRoles + - counts.DatabaseStaticRoles + - counts.GCPStaticAccounts + - counts.GCPImpersonatedAccounts + - counts.LDAPStaticRoles + - counts.OpenLDAPStaticRoles + awsCount = counts.AWSStaticRoles + azureCount = counts.AzureStaticRoles + databaseCount = counts.DatabaseStaticRoles + gcpStaticCount = counts.GCPStaticAccounts + gcpImpersonatedCount = counts.GCPImpersonatedAccounts + ldapCount = counts.LDAPStaticRoles + openldapCount = counts.OpenLDAPStaticRoles + + total = awsCount + azureCount + databaseCount + gcpStaticCount + + gcpImpersonatedCount + ldapCount + openldapCount } - details := []map[string]interface{}{} - if counts != nil { - if counts.AWSStaticRoles > 0 { - details = append(details, map[string]interface{}{"type": "aws_static", "count": counts.AWSStaticRoles}) - } - if counts.AzureStaticRoles > 0 { - details = append(details, map[string]interface{}{"type": "azure_static", "count": counts.AzureStaticRoles}) - } - if counts.DatabaseStaticRoles > 0 { - details = append(details, map[string]interface{}{"type": "database_static", "count": counts.DatabaseStaticRoles}) - } - if counts.GCPStaticAccounts > 0 { - details = append(details, map[string]interface{}{"type": "gcp_static", "count": counts.GCPStaticAccounts}) - } - if counts.GCPImpersonatedAccounts > 0 { - details = append(details, map[string]interface{}{"type": "gcp_impersonated", "count": counts.GCPImpersonatedAccounts}) - } - if counts.LDAPStaticRoles > 0 { - details = append(details, map[string]interface{}{"type": "ldap_static", "count": counts.LDAPStaticRoles}) - } - if counts.OpenLDAPStaticRoles > 0 { - details = append(details, map[string]interface{}{"type": "openldap_static", "count": counts.OpenLDAPStaticRoles}) - } + details := []map[string]interface{}{ + {"type": "aws_static", "count": awsCount}, + {"type": "azure_static", "count": azureCount}, + {"type": "database_static", "count": databaseCount}, + {"type": "gcp_static", "count": gcpStaticCount}, + {"type": "gcp_impersonated", "count": gcpImpersonatedCount}, + {"type": "ldap_static", "count": ldapCount}, + {"type": "openldap_static", "count": openldapCount}, } return map[string]interface{}{ @@ -415,16 +393,11 @@ func (b *SystemBackend) buildPkiBillingMetric(ctx context.Context, month time.Ti func (b *SystemBackend) buildIdTokenUnitsBillingMetric(ctx context.Context, month time.Time) (map[string]interface{}, error) { var totalTokens float64 - idTokenDetails := []map[string]interface{}{} oidcTokenCount, err := b.Core.GetStoredOidcDurationAdjustedCount(ctx, month) if err != nil { return nil, fmt.Errorf("error retrieving OIDC duration-adjusted token count for month: %w", err) } - if oidcTokenCount > 0 { - idTokenDetails = append(idTokenDetails, map[string]interface{}{"type": "oidc", "count": oidcTokenCount}) - } - totalTokens += oidcTokenCount spiffeJwtUnits, err := b.Core.GetStoredSpiffeJwtTokenUnits(ctx, month) @@ -432,12 +405,13 @@ func (b *SystemBackend) buildIdTokenUnitsBillingMetric(ctx context.Context, mont return nil, fmt.Errorf("error retrieving JWT Spiffe duration-adjusted token count for month: %w", err) } - if spiffeJwtUnits > 0 { - idTokenDetails = append(idTokenDetails, map[string]interface{}{"type": "spiffe", "count": spiffeJwtUnits}) - } - totalTokens += spiffeJwtUnits + idTokenDetails := []map[string]interface{}{ + {"type": "oidc", "count": oidcTokenCount}, + {"type": "spiffe", "count": spiffeJwtUnits}, + } + return map[string]interface{}{ "metric_name": "id_token_units", "metric_data": map[string]interface{}{ diff --git a/vault/logical_system_use_case_billing_test.go b/vault/logical_system_use_case_billing_test.go index 2c1673d1cf..b3229cd166 100644 --- a/vault/logical_system_use_case_billing_test.go +++ b/vault/logical_system_use_case_billing_test.go @@ -618,14 +618,33 @@ func TestSystemBackend_BillingOverview_EmptyMetrics(t *testing.T) { // Verify each metric has appropriate zero value switch metricName { - case "static_secrets", "dynamic_roles", "auto_rotated_roles": + case "static_secrets": total, ok := metricData["total"].(int) require.True(t, ok, "%s total should be int", metricName) require.Equal(t, 0, total, "%s total should be 0", metricName) details, ok := metricData["metric_details"].([]map[string]interface{}) require.True(t, ok, "%s metric_details should be array", metricName) - require.Empty(t, details, "%s metric_details should be empty when total is 0", metricName) + require.NotEmpty(t, details, "%s metric_details should always be present", metricName) + // Verify kv type is present with zero count + require.Len(t, details, 1) + require.Equal(t, "kv", details[0]["type"]) + require.Equal(t, 0, details[0]["count"]) + + case "dynamic_roles", "auto_rotated_roles": + total, ok := metricData["total"].(int) + require.True(t, ok, "%s total should be int", metricName) + require.Equal(t, 0, total, "%s total should be 0", metricName) + + details, ok := metricData["metric_details"].([]map[string]interface{}) + require.True(t, ok, "%s metric_details should be array", metricName) + require.NotEmpty(t, details, "%s metric_details should always be present", metricName) + // Verify all role types are present with zero counts + for _, detail := range details { + require.Contains(t, detail, "type") + require.Contains(t, detail, "count") + require.Equal(t, 0, detail["count"]) + } case "kmip": used, ok := metricData["used_in_month"].(bool) @@ -644,7 +663,18 @@ func TestSystemBackend_BillingOverview_EmptyMetrics(t *testing.T) { details, ok := metricData["metric_details"].([]map[string]interface{}) require.True(t, ok, "data_protection_calls metric_details should be array") - require.Empty(t, details, "data_protection_calls metric_details should be empty when total is 0") + require.NotEmpty(t, details, "data_protection_calls metric_details should always be present") + // Verify all data protection types are present with zero counts + require.Len(t, details, 3) + expectedTypes := map[string]bool{"transit": false, "transform": false, "gcpkms": false} + for _, detail := range details { + detailType := detail["type"].(string) + expectedTypes[detailType] = true + require.Equal(t, uint64(0), detail["count"]) + } + for typeName, found := range expectedTypes { + require.True(t, found, "type %s should be present", typeName) + } case "pki_units": total, ok := metricData["total"].(float64) @@ -653,11 +683,22 @@ func TestSystemBackend_BillingOverview_EmptyMetrics(t *testing.T) { case "managed_keys": total, ok := metricData["total"].(int) - require.True(t, ok, "managed_keys total should be float64") + require.True(t, ok, "managed_keys total should be int") require.Equal(t, int(0), total, "managed keys total should be 0") details, ok := metricData["metric_details"].([]map[string]interface{}) require.True(t, ok, "%s metric_details should be array", metricName) - require.Empty(t, details, "%s metric_details should be empty when total is 0", metricName) + require.NotEmpty(t, details, "%s metric_details should always be present", metricName) + // Verify both managed key types are present with zero counts + require.Len(t, details, 2) + expectedTypes := map[string]bool{"totp": false, "kmse": false} + for _, detail := range details { + detailType := detail["type"].(string) + expectedTypes[detailType] = true + require.Equal(t, 0, detail["count"]) + } + for typeName, found := range expectedTypes { + require.True(t, found, "type %s should be present", typeName) + } case "ssh_units": total, ok := metricData["total"].(float64) @@ -668,6 +709,21 @@ func TestSystemBackend_BillingOverview_EmptyMetrics(t *testing.T) { total, ok := metricData["total"].(float64) require.True(t, ok, "id_token_units total should be float64") require.Equal(t, float64(0), total, "id_token_units total should be 0") + + details, ok := metricData["metric_details"].([]map[string]interface{}) + require.True(t, ok, "id_token_units metric_details should be array") + require.NotEmpty(t, details, "id_token_units metric_details should always be present") + // Verify both token types are present with zero counts + require.Len(t, details, 2) + expectedTypes := map[string]bool{"oidc": false, "spiffe": false} + for _, detail := range details { + detailType := detail["type"].(string) + expectedTypes[detailType] = true + require.Equal(t, float64(0), detail["count"]) + } + for typeName, found := range expectedTypes { + require.True(t, found, "type %s should be present", typeName) + } } } @@ -941,6 +997,135 @@ func TestSystemBackend_BillingOverview_UpdatedAtTimestamp_NoStoredTimestamp(t *t "previous month updated_at should be zero time when no stored timestamp exists") } +// TestSystemBackend_BillingOverview_AllMetricTypesPresent verifies that all metric types +// are always present in the response, even when their counts are zero. This test specifically +// validates that metric_details arrays contain all expected types for each metric category. +func TestSystemBackend_BillingOverview_AllMetricTypesPresent(t *testing.T) { + _, b, _ := testCoreSystemBackend(t) + ctx := namespace.RootContext(nil) + + // Make a request without creating any billable resources + req := logical.TestRequest(t, logical.ReadOperation, "billing/overview") + resp, err := b.HandleRequest(ctx, req) + require.NoError(t, err) + require.NotNil(t, resp) + require.NotNil(t, resp.Data) + + // Verify the response structure exists + months, ok := resp.Data["months"].([]interface{}) + require.True(t, ok) + require.Len(t, months, billing.BillingRetentionMonths) + + // Check current month has all metrics + currentMonth, ok := months[0].(map[string]interface{}) + require.True(t, ok) + require.Contains(t, currentMonth, "usage_metrics") + + usageMetrics, ok := currentMonth["usage_metrics"].([]map[string]interface{}) + require.True(t, ok) + require.NotNil(t, usageMetrics) + require.NotEmpty(t, usageMetrics, "usage_metrics should contain all metrics even with zero values") + + // Build a map of metrics for easy lookup + metricsMap := make(map[string]map[string]interface{}) + for _, metric := range usageMetrics { + metricName, ok := metric["metric_name"].(string) + require.True(t, ok, "metric_name should be a string") + metricsMap[metricName] = metric + } + + // Verify static_secrets has kv type + staticSecretsMetric, exists := metricsMap["static_secrets"] + require.True(t, exists, "static_secrets metric should be present") + staticSecretsData := staticSecretsMetric["metric_data"].(map[string]interface{}) + staticSecretsDetails := staticSecretsData["metric_details"].([]map[string]interface{}) + require.Len(t, staticSecretsDetails, 1, "static_secrets should have 1 type") + require.Equal(t, "kv", staticSecretsDetails[0]["type"]) + require.Equal(t, 0, staticSecretsDetails[0]["count"]) + + // Verify dynamic_roles has all 13 types + dynamicRolesMetric, exists := metricsMap["dynamic_roles"] + require.True(t, exists, "dynamic_roles metric should be present") + dynamicRolesData := dynamicRolesMetric["metric_data"].(map[string]interface{}) + dynamicRolesDetails := dynamicRolesData["metric_details"].([]map[string]interface{}) + require.Len(t, dynamicRolesDetails, 13, "dynamic_roles should have 13 types") + + expectedDynamicTypes := []string{ + "aws_dynamic", "azure_dynamic", "database_dynamic", "gcp_dynamic", + "ldap_dynamic", "openldap_dynamic", "alicloud_dynamic", "rabbitmq_dynamic", + "consul_dynamic", "nomad_dynamic", "kubernetes_dynamic", "mongodbatlas_dynamic", + "terraform_dynamic", + } + for i, expectedType := range expectedDynamicTypes { + require.Equal(t, expectedType, dynamicRolesDetails[i]["type"], "dynamic role type at index %d should be %s", i, expectedType) + require.Equal(t, 0, dynamicRolesDetails[i]["count"], "dynamic role count at index %d should be 0", i) + } + + // Verify auto_rotated_roles has all 7 types + autoRotatedMetric, exists := metricsMap["auto_rotated_roles"] + require.True(t, exists, "auto_rotated_roles metric should be present") + autoRotatedData := autoRotatedMetric["metric_data"].(map[string]interface{}) + autoRotatedDetails := autoRotatedData["metric_details"].([]map[string]interface{}) + require.Len(t, autoRotatedDetails, 7, "auto_rotated_roles should have 7 types") + + expectedAutoRotatedTypes := []string{ + "aws_static", "azure_static", "database_static", "gcp_static", + "gcp_impersonated", "ldap_static", "openldap_static", + } + for i, expectedType := range expectedAutoRotatedTypes { + require.Equal(t, expectedType, autoRotatedDetails[i]["type"], "auto-rotated role type at index %d should be %s", i, expectedType) + require.Equal(t, 0, autoRotatedDetails[i]["count"], "auto-rotated role count at index %d should be 0", i) + } + + // Verify data_protection_calls has all 3 types + dataProtectionMetric, exists := metricsMap["data_protection_calls"] + require.True(t, exists, "data_protection_calls metric should be present") + dataProtectionData := dataProtectionMetric["metric_data"].(map[string]interface{}) + dataProtectionDetails := dataProtectionData["metric_details"].([]map[string]interface{}) + require.Len(t, dataProtectionDetails, 3, "data_protection_calls should have 3 types") + + expectedDataProtectionTypes := []string{"transit", "transform", "gcpkms"} + for i, expectedType := range expectedDataProtectionTypes { + require.Equal(t, expectedType, dataProtectionDetails[i]["type"], "data protection type at index %d should be %s", i, expectedType) + require.Equal(t, uint64(0), dataProtectionDetails[i]["count"], "data protection count at index %d should be 0", i) + } + + // Verify managed_keys has both types + managedKeysMetric, exists := metricsMap["managed_keys"] + require.True(t, exists, "managed_keys metric should be present") + managedKeysData := managedKeysMetric["metric_data"].(map[string]interface{}) + managedKeysDetails := managedKeysData["metric_details"].([]map[string]interface{}) + require.Len(t, managedKeysDetails, 2, "managed_keys should have 2 types") + + expectedManagedKeyTypes := []string{"totp", "kmse"} + for i, expectedType := range expectedManagedKeyTypes { + require.Equal(t, expectedType, managedKeysDetails[i]["type"], "managed key type at index %d should be %s", i, expectedType) + require.Equal(t, 0, managedKeysDetails[i]["count"], "managed key count at index %d should be 0", i) + } + + // Verify ssh_units has both types + sshMetric, exists := metricsMap["ssh_units"] + require.True(t, exists, "ssh_units metric should be present") + sshData := sshMetric["metric_data"].(map[string]interface{}) + sshDetails := sshData["metric_details"].([]map[string]interface{}) + require.Len(t, sshDetails, 2, "ssh_units should have 2 types") + require.Equal(t, "otp_units", sshDetails[0]["type"]) + require.Equal(t, "certificate_units", sshDetails[1]["type"]) + + // Verify id_token_units has both types + idTokenMetric, exists := metricsMap["id_token_units"] + require.True(t, exists, "id_token_units metric should be present") + idTokenData := idTokenMetric["metric_data"].(map[string]interface{}) + idTokenDetails := idTokenData["metric_details"].([]map[string]interface{}) + require.Len(t, idTokenDetails, 2, "id_token_units should have 2 types") + + expectedIdTokenTypes := []string{"oidc", "spiffe"} + for i, expectedType := range expectedIdTokenTypes { + require.Equal(t, expectedType, idTokenDetails[i]["type"], "id token type at index %d should be %s", i, expectedType) + require.Equal(t, float64(0), idTokenDetails[i]["count"], "id token count at index %d should be 0", i) + } +} + // TestSystemBackend_BillingOverview_PreviousMonth_WithError tests the behavior // when retrieving the previous month's timestamp fails with an error. // This ensures the endpoint gracefully handles storage errors by returning zero time.