fix: transactional env var save, empty key validation, frontend error handling
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:
clawbot
2026-03-10 12:25:35 -07:00
parent df6aad9b21
commit 5a986aa8fd
4 changed files with 96 additions and 33 deletions

View File

@@ -1,4 +1,3 @@
//nolint:dupl // Active Record pattern - similar structure to label.go is intentional
package models
import (
@@ -139,3 +138,49 @@ func DeleteEnvVarsByAppID(
return err
}
// EnvVarPair is a key-value pair for bulk env var operations.
type EnvVarPair struct {
Key string
Value string
}
// ReplaceEnvVarsByAppID atomically replaces all env vars for an app
// within a single database transaction. It deletes all existing env
// vars and inserts the provided pairs. If any operation fails, the
// entire transaction is rolled back.
func ReplaceEnvVarsByAppID(
ctx context.Context,
db *database.Database,
appID string,
pairs []EnvVarPair,
) error {
tx, err := db.BeginTx(ctx, nil)
if err != nil {
return fmt.Errorf("beginning transaction: %w", err)
}
defer func() { _ = tx.Rollback() }()
_, err = tx.ExecContext(ctx, "DELETE FROM app_env_vars WHERE app_id = ?", appID)
if err != nil {
return fmt.Errorf("deleting env vars: %w", err)
}
for _, p := range pairs {
_, err = tx.ExecContext(ctx,
"INSERT INTO app_env_vars (app_id, key, value) VALUES (?, ?, ?)",
appID, p.Key, p.Value,
)
if err != nil {
return fmt.Errorf("inserting env var %q: %w", p.Key, err)
}
}
err = tx.Commit()
if err != nil {
return fmt.Errorf("committing transaction: %w", err)
}
return nil
}

View File

@@ -1,4 +1,3 @@
//nolint:dupl // Active Record pattern - similar structure to env_var.go is intentional
package models
import (