Skip to content

Commit f4cb19b

Browse files
authored
fix(controlplane): exclude soft-deleted rows when finding a project version by name (#3237)
Signed-off-by: Miguel Martinez Trivino <miguel@chainloop.dev>
1 parent b80aa21 commit f4cb19b

2 files changed

Lines changed: 30 additions & 2 deletions

File tree

app/controlplane/pkg/biz/projectversion_integration_test.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,35 @@ func (s *ProjectVersionIntegrationTestSuite) TestMarkAsLatestInvalidUUID() {
198198
require.Error(t, err)
199199
}
200200

201+
// Regression test for PFM-6470: a version that was deleted and recreated with the
202+
// same name leaves a soft-deleted row alongside the active one. Looking the version
203+
// up by name must return the active row instead of crashing because the query matched
204+
// more than one row.
205+
func (s *ProjectVersionIntegrationTestSuite) TestFindByProjectAndVersionIgnoresSoftDeleted() {
206+
t := s.T()
207+
ctx := context.Background()
208+
209+
// Create a version and soft-delete it, simulating a delete from the UI/API.
210+
deleted, err := s.ProjectVersion.Create(ctx, s.project.ID.String(), "v17", true)
211+
require.NoError(t, err)
212+
213+
_, err = s.Data.DB.ProjectVersion.UpdateOneID(deleted.ID).SetDeletedAt(time.Now()).Save(ctx)
214+
require.NoError(t, err)
215+
216+
// Recreate a version with the same name; now two rows share version "v17"
217+
// (one soft-deleted, one active).
218+
recreated, err := s.ProjectVersion.Create(ctx, s.project.ID.String(), "v17", true)
219+
require.NoError(t, err)
220+
require.NotEqual(t, deleted.ID, recreated.ID)
221+
222+
// Looking up "v17" must return the active row, not error out because the query
223+
// matched both the soft-deleted and the active row.
224+
found, err := s.ProjectVersion.FindByProjectAndVersion(ctx, s.project.ID.String(), "v17")
225+
require.NoError(t, err)
226+
require.NotNil(t, found)
227+
require.Equal(t, recreated.ID, found.ID)
228+
}
229+
201230
func TestProjectVersionUseCase(t *testing.T) {
202231
suite.Run(t, new(ProjectVersionIntegrationTestSuite))
203232
}

app/controlplane/pkg/data/projectversion.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import (
2121

2222
"github.com/chainloop-dev/chainloop/app/controlplane/pkg/biz"
2323
"github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent"
24-
"github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/project"
2524
"github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/projectversion"
2625
"github.com/chainloop-dev/chainloop/pkg/otelx"
2726
"github.com/go-kratos/kratos/v2/log"
@@ -46,7 +45,7 @@ func (r *ProjectVersionRepo) FindByProjectAndVersion(ctx context.Context, projec
4645
ctx, span := otelx.Start(ctx, projectVersionRepoTracer, "ProjectVersionRepo.FindByProjectAndVersion")
4746
defer span.End()
4847

49-
pv, err := r.data.DB.ProjectVersion.Query().Where(projectversion.HasProjectWith(project.ID(projectID)), projectversion.VersionEQ(version)).Only(ctx)
48+
pv, err := findProjectVersionWithClient(ctx, r.data.DB, projectID, version)
5049
if err != nil && !ent.IsNotFound(err) {
5150
return nil, err
5251
} else if pv == nil {

0 commit comments

Comments
 (0)