From 9f87f4238096c35f8b63f05b3d8842c15ce4b333 Mon Sep 17 00:00:00 2001 From: Jeremy Schoemaker Date: Tue, 25 Aug 2026 19:04:40 -0500 Subject: [PATCH 1/3] fix(helm): sync custom_labels_v1 on Update MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix verified RED->GREEN. SQL driver Update never syncs custom_labels_v1 — label changes silently dropped at sql.go:579 Signed-off-by: Jeremy Schoemaker --- pkg/storage/driver/sql.go | 60 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/pkg/storage/driver/sql.go b/pkg/storage/driver/sql.go index db076da98..a5f740dc8 100644 --- a/pkg/storage/driver/sql.go +++ b/pkg/storage/driver/sql.go @@ -593,6 +593,12 @@ func (s *SQL) Update(key string, rel release.Releaser) error { return err } + transaction, err := s.db.Beginx() + if err != nil { + s.Logger().Debug("failed to start SQL transaction", slog.Any("error", err)) + return fmt.Errorf("error beginning transaction: %w", err) + } + query, args, err := s.statementBuilder. Update(sqlReleaseTableName). Set(sqlReleaseTableBodyColumn, body). @@ -605,15 +611,67 @@ func (s *SQL) Update(key string, rel release.Releaser) error { Where(sq.Eq{sqlReleaseTableNamespaceColumn: namespace}). ToSql() if err != nil { + transaction.Rollback() s.Logger().Debug("failed to build update query", slog.Any("error", err)) return err } - if _, err := s.db.Exec(query, args...); err != nil { + if _, err := transaction.Exec(query, args...); err != nil { + transaction.Rollback() s.Logger().Debug("failed to update release in SQL database", slog.String("key", key), slog.Any("error", err)) return err } + deleteQuery, args, err := s.statementBuilder. + Delete(sqlCustomLabelsTableName). + Where(sq.Eq{sqlCustomLabelsTableReleaseKeyColumn: key}). + Where(sq.Eq{sqlCustomLabelsTableReleaseNamespaceColumn: namespace}). + ToSql() + if err != nil { + transaction.Rollback() + s.Logger().Debug("failed to build delete Labels query", slog.Any("error", err)) + return err + } + + if _, err := transaction.Exec(deleteQuery, args...); err != nil { + transaction.Rollback() + s.Logger().Debug("failed to delete Labels", slog.Any("error", err)) + return err + } + + for k, v := range filterSystemLabels(rls.Labels) { + insertLabelsQuery, args, err := s.statementBuilder. + Insert(sqlCustomLabelsTableName). + Columns( + sqlCustomLabelsTableReleaseKeyColumn, + sqlCustomLabelsTableReleaseNamespaceColumn, + sqlCustomLabelsTableKeyColumn, + sqlCustomLabelsTableValueColumn, + ). + Values( + key, + namespace, + k, + v, + ).ToSql() + if err != nil { + transaction.Rollback() + s.Logger().Debug("failed to build insert query", slog.Any("error", err)) + return err + } + + if _, err := transaction.Exec(insertLabelsQuery, args...); err != nil { + transaction.Rollback() + s.Logger().Debug("failed to write Labels", slog.Any("error", err)) + return err + } + } + + if err := transaction.Commit(); err != nil { + s.Logger().Debug("failed to commit transaction", slog.Any("error", err)) + return err + } + return nil } From f1eb1698e1889352d2dce1f42562ce8cf7e48cfe Mon Sep 17 00:00:00 2001 From: Jeremy Schoemaker Date: Thu, 27 Aug 2026 15:43:54 -0500 Subject: [PATCH 2/3] fix(helm): rollback transaction on failed Commit in Update Signed-off-by: Jeremy Schoemaker --- pkg/storage/driver/sql.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/storage/driver/sql.go b/pkg/storage/driver/sql.go index a5f740dc8..71807c049 100644 --- a/pkg/storage/driver/sql.go +++ b/pkg/storage/driver/sql.go @@ -668,6 +668,7 @@ func (s *SQL) Update(key string, rel release.Releaser) error { } if err := transaction.Commit(); err != nil { + transaction.Rollback() s.Logger().Debug("failed to commit transaction", slog.Any("error", err)) return err } From 879461e499b4643d31f25b84bd5e862638d86209 Mon Sep 17 00:00:00 2001 From: Jeremy Schoemaker Date: Tue, 8 Sep 2026 15:31:27 -0500 Subject: [PATCH 3/3] fix(helm): update TestSqlUpdate to assert label sync transaction Signed-off-by: Jeremy Schoemaker --- pkg/storage/driver/sql_test.go | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/pkg/storage/driver/sql_test.go b/pkg/storage/driver/sql_test.go index 044e9df7b..6c24ce4a4 100644 --- a/pkg/storage/driver/sql_test.go +++ b/pkg/storage/driver/sql_test.go @@ -309,11 +309,40 @@ func TestSqlUpdate(t *testing.T) { sqlReleaseTableNamespaceColumn, ) + mock.ExpectBegin() mock. ExpectExec(regexp.QuoteMeta(query)). WithArgs(body, rel.Name, int(rel.Version), rel.Info.Status.String(), sqlReleaseDefaultOwner, recentUnixTimestamp(), key, namespace). WillReturnResult(sqlmock.NewResult(0, 1)) + deleteLabelsQuery := fmt.Sprintf( + "DELETE FROM %s WHERE %s = $1 AND %s = $2", + sqlCustomLabelsTableName, + sqlCustomLabelsTableReleaseKeyColumn, + sqlCustomLabelsTableReleaseNamespaceColumn, + ) + mock. + ExpectExec(regexp.QuoteMeta(deleteLabelsQuery)). + WithArgs(key, namespace). + WillReturnResult(sqlmock.NewResult(0, 1)) + + insertLabelsQuery := fmt.Sprintf( + "INSERT INTO %s (%s,%s,%s,%s) VALUES ($1,$2,$3,$4)", + sqlCustomLabelsTableName, + sqlCustomLabelsTableReleaseKeyColumn, + sqlCustomLabelsTableReleaseNamespaceColumn, + sqlCustomLabelsTableKeyColumn, + sqlCustomLabelsTableValueColumn, + ) + mock.MatchExpectationsInOrder(false) + for k, v := range filterSystemLabels(rel.Labels) { + mock. + ExpectExec(regexp.QuoteMeta(insertLabelsQuery)). + WithArgs(key, namespace, k, v). + WillReturnResult(sqlmock.NewResult(0, 1)) + } + mock.ExpectCommit() + require.NoErrorf(t, sqlDriver.Update(key, rel), "failed to update release with key %s", key) assert.NoErrorf(t, mock.ExpectationsWereMet(), "sql expectations weren't met") }