From 1e57029ad5e504a4e2a8891fc45ecaf0ba0f4620 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 16 Jan 2026 11:59:39 -0800 Subject: [PATCH] Follow @wxiaoguang's suggestion --- models/repo/release.go | 11 +++++++++++ models/repo/release_test.go | 39 +++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/models/repo/release.go b/models/repo/release.go index 68fb6b1724..bc136c6a84 100644 --- a/models/repo/release.go +++ b/models/repo/release.go @@ -93,6 +93,10 @@ func init() { db.RegisterModel(new(Release)) } +// legacyAttachmentMissingRepoIDCutoff marks the date when repo_id started to be written during uploads +// (2026-01-16T00:00:00Z). Older rows might have repo_id=0 and should be tolerated once. +const legacyAttachmentMissingRepoIDCutoff timeutil.TimeStamp = 1768521600 + func (r *Release) LoadRepo(ctx context.Context) (err error) { if r.Repo != nil { return nil @@ -186,6 +190,13 @@ func AddReleaseAttachments(ctx context.Context, releaseID int64, attachmentUUIDs } for i := range attachments { + if attachments[i].RepoID == 0 && attachments[i].CreatedUnix < legacyAttachmentMissingRepoIDCutoff { + attachments[i].RepoID = rel.RepoID + if _, err = db.GetEngine(ctx).ID(attachments[i].ID).Cols("repo_id").Update(attachments[i]); err != nil { + return fmt.Errorf("update attachment repo_id [%d]: %w", attachments[i].ID, err) + } + } + if attachments[i].RepoID != rel.RepoID { return util.NewPermissionDeniedErrorf("attachment belongs to different repository") } diff --git a/models/repo/release_test.go b/models/repo/release_test.go index 8e30e76f49..abf50b1edb 100644 --- a/models/repo/release_test.go +++ b/models/repo/release_test.go @@ -6,6 +6,7 @@ package repo import ( "testing" + "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/modules/util" @@ -51,3 +52,41 @@ func TestAddReleaseAttachmentsRejectsDifferentRepo(t *testing.T) { assert.NoError(t, err) assert.Zero(t, attach.ReleaseID, "attachment should not be linked to release on failure") } + +func TestAddReleaseAttachmentsAllowsLegacyMissingRepoID(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + legacyUUID := "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a20" // attachment 10 has repo_id 0 + err := AddReleaseAttachments(t.Context(), 1, []string{legacyUUID}) + assert.NoError(t, err) + + attach, err := GetAttachmentByUUID(t.Context(), legacyUUID) + assert.NoError(t, err) + assert.EqualValues(t, 1, attach.RepoID) + assert.EqualValues(t, 1, attach.ReleaseID) +} + +func TestAddReleaseAttachmentsRejectsRecentZeroRepoID(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + recentUUID := "a0eebc99-9c0b-4ef8-bb6d-6bb9bd3800aa" + attachment := &Attachment{ + UUID: recentUUID, + RepoID: 0, + IssueID: 0, + ReleaseID: 0, + CommentID: 0, + Name: "recent-zero", + CreatedUnix: legacyAttachmentMissingRepoIDCutoff + 1, + } + assert.NoError(t, db.Insert(t.Context(), attachment)) + + err := AddReleaseAttachments(t.Context(), 1, []string{recentUUID}) + assert.Error(t, err) + assert.ErrorIs(t, err, util.ErrPermissionDenied) + + attach, err := GetAttachmentByUUID(t.Context(), recentUUID) + assert.NoError(t, err) + assert.Zero(t, attach.ReleaseID) + assert.Zero(t, attach.RepoID) +}