fix: transactional env var save, empty key validation, frontend error handling
All checks were successful
Check / check (pull_request) Successful in 4s
All checks were successful
Check / check (pull_request) Successful in 4s
- Wrap DELETE + INSERTs in a database transaction via new ReplaceEnvVarsByAppID() to prevent silent data loss on partial insert failure. Rollback on any error; return 500 instead of 200. - Add server-side validation rejecting entries with empty keys (returns 400 with error message). - Add frontend error handling for non-2xx responses with user-visible alert messages. - Remove stale //nolint:dupl directives (files no longer duplicate).
This commit is contained in:
@@ -912,7 +912,7 @@ type envPairJSON struct {
|
||||
// HandleEnvVarSave handles bulk saving of all environment variables.
|
||||
// It reads a JSON array of {key, value} objects from the request body,
|
||||
// deletes all existing env vars for the app, and inserts the full
|
||||
// submitted set.
|
||||
// submitted set atomically within a database transaction.
|
||||
func (h *Handlers) HandleEnvVarSave() http.HandlerFunc {
|
||||
return func(writer http.ResponseWriter, request *http.Request) {
|
||||
appID := chi.URLParam(request, "id")
|
||||
@@ -933,36 +933,36 @@ func (h *Handlers) HandleEnvVarSave() http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
ctx := request.Context()
|
||||
// Validate: reject entries with empty keys
|
||||
var modelPairs []models.EnvVarPair
|
||||
|
||||
// Delete all existing env vars for this app
|
||||
deleteErr := models.DeleteEnvVarsByAppID(ctx, h.db, application.ID)
|
||||
if deleteErr != nil {
|
||||
h.log.Error("failed to delete env vars", "error", deleteErr)
|
||||
http.Error(
|
||||
writer,
|
||||
"Internal Server Error",
|
||||
http.StatusInternalServerError,
|
||||
)
|
||||
for _, p := range pairs {
|
||||
trimmedKey := strings.TrimSpace(p.Key)
|
||||
if trimmedKey == "" {
|
||||
h.respondJSON(writer, request, map[string]string{
|
||||
"error": "empty environment variable key is not allowed",
|
||||
}, http.StatusBadRequest)
|
||||
|
||||
return
|
||||
return
|
||||
}
|
||||
|
||||
modelPairs = append(modelPairs, models.EnvVarPair{
|
||||
Key: trimmedKey,
|
||||
Value: p.Value,
|
||||
})
|
||||
}
|
||||
|
||||
// Insert the full new set
|
||||
for _, p := range pairs {
|
||||
envVar := models.NewEnvVar(h.db)
|
||||
envVar.AppID = application.ID
|
||||
envVar.Key = p.Key
|
||||
envVar.Value = p.Value
|
||||
// Atomically replace all env vars in a transaction
|
||||
ctx := request.Context()
|
||||
|
||||
saveErr := envVar.Save(ctx)
|
||||
if saveErr != nil {
|
||||
h.log.Error(
|
||||
"failed to save env var",
|
||||
"key", p.Key,
|
||||
"error", saveErr,
|
||||
)
|
||||
}
|
||||
replaceErr := models.ReplaceEnvVarsByAppID(ctx, h.db, application.ID, modelPairs)
|
||||
if replaceErr != nil {
|
||||
h.log.Error("failed to replace env vars", "error", replaceErr)
|
||||
h.respondJSON(writer, request, map[string]string{
|
||||
"error": "failed to save environment variables",
|
||||
}, http.StatusInternalServerError)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
h.respondJSON(writer, request, map[string]bool{"ok": true}, http.StatusOK)
|
||||
|
||||
Reference in New Issue
Block a user