forked from wrenn/wrenn
Fix API key cleanup on user deactivation and build archive race condition
Delete all API keys created by a user when their account is disabled, deleted, or soft-deleted. Store build archives before enqueuing to Redis so workers never dequeue a build with missing files.
This commit is contained in:
@ -25,3 +25,6 @@ UPDATE team_api_keys SET last_used = NOW() WHERE id = $1;
|
|||||||
|
|
||||||
-- name: DeleteAPIKeysByTeam :exec
|
-- name: DeleteAPIKeysByTeam :exec
|
||||||
DELETE FROM team_api_keys WHERE team_id = $1;
|
DELETE FROM team_api_keys WHERE team_id = $1;
|
||||||
|
|
||||||
|
-- name: DeleteAPIKeysByCreator :exec
|
||||||
|
DELETE FROM team_api_keys WHERE created_by = $1;
|
||||||
|
|||||||
@ -524,6 +524,10 @@ func (h *meHandler) DeleteAccount(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := h.db.DeleteAPIKeysByCreator(ctx, ac.UserID); err != nil {
|
||||||
|
slog.Warn("account delete: failed to delete user's API keys", "error", err)
|
||||||
|
}
|
||||||
|
|
||||||
if err := h.db.SoftDeleteUser(ctx, ac.UserID); err != nil {
|
if err := h.db.SoftDeleteUser(ctx, ac.UserID); err != nil {
|
||||||
writeError(w, http.StatusInternalServerError, "db_error", "failed to delete account")
|
writeError(w, http.StatusInternalServerError, "db_error", "failed to delete account")
|
||||||
return
|
return
|
||||||
|
|||||||
@ -25,6 +25,15 @@ func (q *Queries) DeleteAPIKey(ctx context.Context, arg DeleteAPIKeyParams) erro
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const deleteAPIKeysByCreator = `-- name: DeleteAPIKeysByCreator :exec
|
||||||
|
DELETE FROM team_api_keys WHERE created_by = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) DeleteAPIKeysByCreator(ctx context.Context, createdBy pgtype.UUID) error {
|
||||||
|
_, err := q.db.Exec(ctx, deleteAPIKeysByCreator, createdBy)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
const deleteAPIKeysByTeam = `-- name: DeleteAPIKeysByTeam :exec
|
const deleteAPIKeysByTeam = `-- name: DeleteAPIKeysByTeam :exec
|
||||||
DELETE FROM team_api_keys WHERE team_id = $1
|
DELETE FROM team_api_keys WHERE team_id = $1
|
||||||
`
|
`
|
||||||
|
|||||||
@ -139,16 +139,16 @@ func (s *BuildService) Create(ctx context.Context, p BuildCreateParams) (db.Temp
|
|||||||
return db.TemplateBuild{}, fmt.Errorf("insert build: %w", err)
|
return db.TemplateBuild{}, fmt.Errorf("insert build: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enqueue build ID (as formatted string) to Redis for workers to pick up.
|
// Store archive before enqueue so the worker never dequeues without files.
|
||||||
if err := s.Redis.RPush(ctx, buildQueueKey, buildIDStr).Err(); err != nil {
|
|
||||||
return db.TemplateBuild{}, fmt.Errorf("enqueue build: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store archive for the worker if provided.
|
|
||||||
if len(p.Archive) > 0 {
|
if len(p.Archive) > 0 {
|
||||||
s.storeArchive(buildIDStr, p.Archive)
|
s.storeArchive(buildIDStr, p.Archive)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := s.Redis.RPush(ctx, buildQueueKey, buildIDStr).Err(); err != nil {
|
||||||
|
s.takeArchive(buildIDStr) // clean up on enqueue failure
|
||||||
|
return db.TemplateBuild{}, fmt.Errorf("enqueue build: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
return build, nil
|
return build, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package service
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jackc/pgx/v5/pgtype"
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
@ -66,5 +67,10 @@ func (s *UserService) SetUserStatus(ctx context.Context, userID pgtype.UUID, sta
|
|||||||
}); err != nil {
|
}); err != nil {
|
||||||
return fmt.Errorf("set user status: %w", err)
|
return fmt.Errorf("set user status: %w", err)
|
||||||
}
|
}
|
||||||
|
if status == "disabled" || status == "deleted" {
|
||||||
|
if err := s.DB.DeleteAPIKeysByCreator(ctx, userID); err != nil {
|
||||||
|
slog.Warn("failed to delete API keys for deactivated user", "user_id", userID, "error", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user