From 5e016c6584e7065c0c8b05ee3f74395d7d5055ad Mon Sep 17 00:00:00 2001 From: mrhid6 Date: Mon, 3 Aug 2026 14:12:21 +0100 Subject: [PATCH] fix: audit ack_notice and stop misreporting DB errors as lockouts ackAuthProviderNotice mutated callback_notice with no audit event; it now writes auth_provider.ack_notice like create/update/delete. guardProviderChange's callers turned any error from CountEnabledAuthProviders into a 409 last_provider, so a transient Mongo error was reported to the operator as an unremovable lockout. Only services.ErrLockout now produces the 409; anything else is a 500. --- server/internal/api/auth_providers.go | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/server/internal/api/auth_providers.go b/server/internal/api/auth_providers.go index 96fcc4a..67ccdc7 100644 --- a/server/internal/api/auth_providers.go +++ b/server/internal/api/auth_providers.go @@ -103,7 +103,11 @@ func updateAuthProvider(c *gin.Context) { } if err := guardProviderChange(instanceID, existing, body.Enabled, false); err != nil { - c.JSON(http.StatusConflict, gin.H{"error": err.Error(), "code": "last_provider"}) + if errors.Is(err, services.ErrLockout) { + c.JSON(http.StatusConflict, gin.H{"error": err.Error(), "code": "last_provider"}) + return + } + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } @@ -144,7 +148,11 @@ func deleteAuthProvider(c *gin.Context) { return } if err := guardProviderChange(instanceID, existing, nil, true); err != nil { - c.JSON(http.StatusConflict, gin.H{"error": err.Error(), "code": "last_provider"}) + if errors.Is(err, services.ErrLockout) { + c.JSON(http.StatusConflict, gin.H{"error": err.Error(), "code": "last_provider"}) + return + } + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } if err := services.DeleteAuthProvider(instanceID, providerID); err != nil { @@ -172,10 +180,17 @@ func guardProviderChange(instanceID string, existing *models.AuthProvider, enabl func ackAuthProviderNotice(c *gin.Context) { instanceID := auth.InstanceID(c) - if err := services.AckAuthProviderNotice(instanceID, c.Param("id")); err != nil { + providerID := c.Param("id") + existing, err := services.GetAuthProvider(instanceID, providerID) + if err != nil { + c.JSON(http.StatusNotFound, gin.H{"error": "provider not found"}) + return + } + if err := services.AckAuthProviderNotice(instanceID, providerID); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } + services.LogEvent(instanceID, "auth_provider.ack_notice", actorFromCtx(c), "", "", existing.Name) c.JSON(http.StatusOK, gin.H{"acknowledged": true}) }