diff --git a/internal/api/handler.go b/internal/api/handler.go index 521a70f8e..752684919 100644 --- a/internal/api/handler.go +++ b/internal/api/handler.go @@ -131,6 +131,11 @@ type Handler struct { // encryption key. Empty when no credStore is configured. Used by the // /health endpoint only — never logged outside that one place. encryptionKeySource string + + // Optional Azure revoke client factory injected by tests. When nil, the + // revoke handlers use the production Azure credential and client + // constructors. + azureRevokeFactory *azureRevokeClientFactory } // getRIUtilizationCache returns the Postgres-backed TTL cache for Cost diff --git a/internal/api/handler_purchases_revoke.go b/internal/api/handler_purchases_revoke.go index f97573f55..a43de2b76 100644 --- a/internal/api/handler_purchases_revoke.go +++ b/internal/api/handler_purchases_revoke.go @@ -93,6 +93,12 @@ type azureCalculateRefundClient interface { Post(ctx context.Context, reservationOrderID string, body armreservations.CalculateRefundRequest, options *armreservations.CalculateRefundClientPostOptions) (armreservations.CalculateRefundClientPostResponse, error) } +type azureRevokeClientFactory struct { + newCredential func() (azcore.TokenCredential, error) + newCalculateRefundClient func(azcore.TokenCredential) (azureCalculateRefundClient, error) + newReturnClient func(azcore.TokenCredential) (azureReturnClient, error) +} + // revokePurchaseResult is the JSON body returned on a successful revocation. type revokePurchaseResult struct { Status string `json:"status"` @@ -409,13 +415,9 @@ func (h *Handler) calculateAzureRevoke(ctx context.Context, req *events.LambdaFu return nil, err } - cred, err := azidentity.NewDefaultAzureCredential(nil) - if err != nil { - return nil, fmt.Errorf("revoke/calculate: obtain credential: %w", err) - } - calcClient, err := armreservations.NewCalculateRefundClient(cred, nil) + calcClient, err := h.buildAzureCalculateRefundClient() if err != nil { - return nil, fmt.Errorf("revoke/calculate: create calculate-refund client: %w", err) + return nil, fmt.Errorf("revoke/calculate: %w", err) } quantity := int32(count) // #nosec G115 -- Azure reservation count bounded by API limits (<