From dc6b98ed9687271534e49c5c70603f15de5112e7 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sat, 10 Jan 2026 16:58:47 -0800 Subject: [PATCH 1/5] Fix release attach repository id not match bug --- models/repo/release.go | 9 +++++++++ models/repo/release_test.go | 14 ++++++++++++++ services/repository/repository.go | 8 +++++++- services/repository/repository_test.go | 19 +++++++++++++++++++ 4 files changed, 49 insertions(+), 1 deletion(-) diff --git a/models/repo/release.go b/models/repo/release.go index 67aa390e6dc45..d2cdfef17e892 100644 --- a/models/repo/release.go +++ b/models/repo/release.go @@ -168,6 +168,11 @@ func UpdateReleaseNumCommits(ctx context.Context, rel *Release) error { // AddReleaseAttachments adds a release attachments func AddReleaseAttachments(ctx context.Context, releaseID int64, attachmentUUIDs []string) (err error) { + rel, err := GetReleaseByID(ctx, releaseID) + if err != nil { + return err + } + // Check attachments attachments, err := GetAttachmentsByUUIDs(ctx, attachmentUUIDs) if err != nil { @@ -175,6 +180,10 @@ func AddReleaseAttachments(ctx context.Context, releaseID int64, attachmentUUIDs } for i := range attachments { + if attachments[i].RepoID != rel.RepoID { + return util.NewPermissionDeniedErrorf("attachment belongs to different repository") + } + if attachments[i].ReleaseID != 0 { return util.NewPermissionDeniedErrorf("release permission denied") } diff --git a/models/repo/release_test.go b/models/repo/release_test.go index 01f0fb3cff78e..8e30e76f490a0 100644 --- a/models/repo/release_test.go +++ b/models/repo/release_test.go @@ -7,6 +7,7 @@ import ( "testing" "code.gitea.io/gitea/models/unittest" + "code.gitea.io/gitea/modules/util" "github.com/stretchr/testify/assert" ) @@ -37,3 +38,16 @@ func Test_FindTagsByCommitIDs(t *testing.T) { assert.Equal(t, "delete-tag", rels[1].TagName) assert.Equal(t, "v1.0", rels[2].TagName) } + +func TestAddReleaseAttachmentsRejectsDifferentRepo(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + uuid := "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a12" // attachment 2 belongs to repo 2 + err := AddReleaseAttachments(t.Context(), 1, []string{uuid}) + assert.Error(t, err) + assert.ErrorIs(t, err, util.ErrPermissionDenied) + + attach, err := GetAttachmentByUUID(t.Context(), uuid) + assert.NoError(t, err) + assert.Zero(t, attach.ReleaseID, "attachment should not be linked to release on failure") +} diff --git a/services/repository/repository.go b/services/repository/repository.go index 4d07cb0e38d40..1e2ee7a11a4f6 100644 --- a/services/repository/repository.go +++ b/services/repository/repository.go @@ -224,6 +224,9 @@ func LinkedRepository(ctx context.Context, a *repo_model.Attachment) (*repo_mode if err != nil { return nil, unit.TypeIssues, err } + if iss.RepoID != a.RepoID { + return nil, -1, errors.New("attachment and issue belong to different repositories") + } repo, err := repo_model.GetRepositoryByID(ctx, iss.RepoID) unitType := unit.TypeIssues if iss.IsPull { @@ -235,7 +238,10 @@ func LinkedRepository(ctx context.Context, a *repo_model.Attachment) (*repo_mode if err != nil { return nil, unit.TypeReleases, err } - repo, err := repo_model.GetRepositoryByID(ctx, rel.RepoID) + if rel.RepoID != a.RepoID { + return nil, -1, errors.New("attachment and release belong to different repositories") + } + repo, err := repo_model.GetRepositoryByID(ctx, a.RepoID) return repo, unit.TypeReleases, err } return nil, -1, nil diff --git a/services/repository/repository_test.go b/services/repository/repository_test.go index 5673a4a16189f..68cb9693bcb64 100644 --- a/services/repository/repository_test.go +++ b/services/repository/repository_test.go @@ -42,6 +42,25 @@ func TestLinkedRepository(t *testing.T) { } } +func TestLinkedRepositoryReleaseMismatchedRepo(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + attach, err := repo_model.GetAttachmentByID(t.Context(), 11) + assert.NoError(t, err) + + originalRepoID := attach.RepoID + attach.RepoID = 1 + _, err = db.GetEngine(t.Context()).ID(attach.ID).Cols("repo_id").Update(attach) + assert.NoError(t, err) + defer func() { + attach.RepoID = originalRepoID + _, _ = db.GetEngine(t.Context()).ID(attach.ID).Cols("repo_id").Update(attach) + }() + + _, _, err = LinkedRepository(t.Context(), attach) + assert.EqualError(t, err, "attachment and release belong to different repositories") +} + func TestUpdateRepositoryVisibilityChanged(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) From ab860263347e568de395f3e60f33166b32ed2509 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 13 Jan 2026 20:24:21 -0800 Subject: [PATCH 2/5] Rework LinkedRepository function --- models/repo/attachment.go | 5 ++++ models/repo/attachment_test.go | 16 ++++++++++++ routers/web/repo/attachment.go | 33 +++++++++++++++++------- services/repository/repository.go | 28 ++++++++------------- services/repository/repository_test.go | 35 +++++--------------------- services/user/user.go | 18 +++++++++++++ services/user/user_test.go | 18 +++++++++++++ 7 files changed, 98 insertions(+), 55 deletions(-) diff --git a/models/repo/attachment.go b/models/repo/attachment.go index 835bee540250d..27856f2d2e2d6 100644 --- a/models/repo/attachment.go +++ b/models/repo/attachment.go @@ -166,6 +166,11 @@ func GetAttachmentByReleaseIDFileName(ctx context.Context, releaseID int64, file return attach, nil } +func GetUnlinkedAttachmentsByUserID(ctx context.Context, userID int64) ([]*Attachment, error) { + attachments := make([]*Attachment, 0, 10) + return attachments, db.GetEngine(ctx).Where("uploader_id = ? AND issue_id = 0 AND release_id = 0 AND comment_id = 0", userID).Find(&attachments) +} + // DeleteAttachment deletes the given attachment and optionally the associated file. func DeleteAttachment(ctx context.Context, a *Attachment, remove bool) error { _, err := DeleteAttachments(ctx, []*Attachment{a}, remove) diff --git a/models/repo/attachment_test.go b/models/repo/attachment_test.go index d41008344d5d0..fdc48d3cdb4b0 100644 --- a/models/repo/attachment_test.go +++ b/models/repo/attachment_test.go @@ -101,3 +101,19 @@ func TestGetAttachmentsByUUIDs(t *testing.T) { assert.Equal(t, int64(1), attachList[0].IssueID) assert.Equal(t, int64(5), attachList[1].IssueID) } + +func TestGetUnlinkedAttachmentsByUserID(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + attachments, err := repo_model.GetUnlinkedAttachmentsByUserID(t.Context(), 8) + assert.NoError(t, err) + assert.Len(t, attachments, 1) + assert.Equal(t, int64(10), attachments[0].ID) + assert.Zero(t, attachments[0].IssueID) + assert.Zero(t, attachments[0].ReleaseID) + assert.Zero(t, attachments[0].CommentID) + + attachments, err = repo_model.GetUnlinkedAttachmentsByUserID(t.Context(), 1) + assert.NoError(t, err) + assert.Len(t, attachments, 0) +} diff --git a/routers/web/repo/attachment.go b/routers/web/repo/attachment.go index 54200d8de8d7f..900222586296f 100644 --- a/routers/web/repo/attachment.go +++ b/routers/web/repo/attachment.go @@ -93,32 +93,47 @@ func ServeAttachment(ctx *context.Context, uuid string) { attach, err := repo_model.GetAttachmentByUUID(ctx, uuid) if err != nil { if repo_model.IsErrAttachmentNotExist(err) { - ctx.HTTPError(http.StatusNotFound) + ctx.NotFound(nil) } else { ctx.ServerError("GetAttachmentByUUID", err) } return } - repository, unitType, err := repo_service.LinkedRepository(ctx, attach) + // prevent visiting attachment from other repository directly + if ctx.Repo.Repository != nil && ctx.Repo.Repository.ID != attach.RepoID { + ctx.NotFound(nil) + return + } + + unitType, err := repo_service.AttachLinkedType(ctx, attach) if err != nil { - ctx.ServerError("LinkedRepository", err) + ctx.ServerError("AttachLinkedType", err) return } - if repository == nil { // If not linked + if unitType == -1 { // unlinked attachment can only be accessed by the uploader if !(ctx.IsSigned && attach.UploaderID == ctx.Doer.ID) { // We block if not the uploader - ctx.HTTPError(http.StatusNotFound) + ctx.NotFound(nil) return } - } else { // If we have the repository we check access - perm, err := access_model.GetUserRepoPermission(ctx, repository, ctx.Doer) + } else { // If we have the linked type, we need to check access + repo := ctx.Repo.Repository + if repo == nil { + repo, err = repo_model.GetRepositoryByID(ctx, attach.RepoID) + if err != nil { + ctx.ServerError("GetRepositoryByID", err) + return + } + } + + perm, err := access_model.GetUserRepoPermission(ctx, repo, ctx.Doer) if err != nil { - ctx.HTTPError(http.StatusInternalServerError, "GetUserRepoPermission", err.Error()) + ctx.ServerError("GetUserRepoPermission", err) return } if !perm.CanRead(unitType) { - ctx.HTTPError(http.StatusNotFound) + ctx.NotFound(nil) return } } diff --git a/services/repository/repository.go b/services/repository/repository.go index 1e2ee7a11a4f6..0966bb8c26ad9 100644 --- a/services/repository/repository.go +++ b/services/repository/repository.go @@ -217,34 +217,28 @@ func MakeRepoPrivate(ctx context.Context, repo *repo_model.Repository) (err erro }) } -// LinkedRepository returns the linked repo if any -func LinkedRepository(ctx context.Context, a *repo_model.Attachment) (*repo_model.Repository, unit.Type, error) { +// AttachLinkedType returns the linked type of attachment if any +func AttachLinkedType(ctx context.Context, a *repo_model.Attachment) (unit.Type, error) { if a.IssueID != 0 { iss, err := issues_model.GetIssueByID(ctx, a.IssueID) if err != nil { - return nil, unit.TypeIssues, err + return unit.TypeIssues, err } - if iss.RepoID != a.RepoID { - return nil, -1, errors.New("attachment and issue belong to different repositories") - } - repo, err := repo_model.GetRepositoryByID(ctx, iss.RepoID) unitType := unit.TypeIssues if iss.IsPull { unitType = unit.TypePullRequests } - return repo, unitType, err - } else if a.ReleaseID != 0 { - rel, err := repo_model.GetReleaseByID(ctx, a.ReleaseID) + return unitType, nil + } + + if a.ReleaseID != 0 { + _, err := repo_model.GetReleaseByID(ctx, a.ReleaseID) if err != nil { - return nil, unit.TypeReleases, err - } - if rel.RepoID != a.RepoID { - return nil, -1, errors.New("attachment and release belong to different repositories") + return unit.TypeReleases, err } - repo, err := repo_model.GetRepositoryByID(ctx, a.RepoID) - return repo, unit.TypeReleases, err + return unit.TypeReleases, nil } - return nil, -1, nil + return -1, nil } // CheckDaemonExportOK creates/removes git-daemon-export-ok for git-daemon... diff --git a/services/repository/repository_test.go b/services/repository/repository_test.go index 68cb9693bcb64..b63a97c1c2f84 100644 --- a/services/repository/repository_test.go +++ b/services/repository/repository_test.go @@ -15,52 +15,29 @@ import ( "github.com/stretchr/testify/assert" ) -func TestLinkedRepository(t *testing.T) { +func TestAttachLinkedType(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) testCases := []struct { name string attachID int64 - expectedRepo *repo_model.Repository expectedUnitType unit.Type }{ - {"LinkedIssue", 1, &repo_model.Repository{ID: 1}, unit.TypeIssues}, - {"LinkedComment", 3, &repo_model.Repository{ID: 1}, unit.TypePullRequests}, - {"LinkedRelease", 9, &repo_model.Repository{ID: 1}, unit.TypeReleases}, - {"Notlinked", 10, nil, -1}, + {"LinkedIssue", 1, unit.TypeIssues}, + {"LinkedComment", 3, unit.TypePullRequests}, + {"LinkedRelease", 9, unit.TypeReleases}, + {"Notlinked", 10, -1}, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { attach, err := repo_model.GetAttachmentByID(t.Context(), tc.attachID) assert.NoError(t, err) - repo, unitType, err := LinkedRepository(t.Context(), attach) + unitType, err := AttachLinkedType(t.Context(), attach) assert.NoError(t, err) - if tc.expectedRepo != nil { - assert.Equal(t, tc.expectedRepo.ID, repo.ID) - } assert.Equal(t, tc.expectedUnitType, unitType) }) } } -func TestLinkedRepositoryReleaseMismatchedRepo(t *testing.T) { - assert.NoError(t, unittest.PrepareTestDatabase()) - - attach, err := repo_model.GetAttachmentByID(t.Context(), 11) - assert.NoError(t, err) - - originalRepoID := attach.RepoID - attach.RepoID = 1 - _, err = db.GetEngine(t.Context()).ID(attach.ID).Cols("repo_id").Update(attach) - assert.NoError(t, err) - defer func() { - attach.RepoID = originalRepoID - _, _ = db.GetEngine(t.Context()).ID(attach.ID).Cols("repo_id").Update(attach) - }() - - _, _, err = LinkedRepository(t.Context(), attach) - assert.EqualError(t, err, "attachment and release belong to different repositories") -} - func TestUpdateRepositoryVisibilityChanged(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) diff --git a/services/user/user.go b/services/user/user.go index 8e42fa3ccdcac..9b8bcf83c0bc7 100644 --- a/services/user/user.go +++ b/services/user/user.go @@ -239,6 +239,11 @@ func DeleteUser(ctx context.Context, u *user_model.User, purge bool) error { if err := deleteUser(ctx, u, purge); err != nil { return fmt.Errorf("DeleteUser: %w", err) } + + // Finally delete any unlinked attachments, this will also delete the attached files + if err := deleteUserUnlinkedAttachments(ctx, u); err != nil { + return fmt.Errorf("deleteUserUnlinkedAttachments: %w", err) + } return nil }); err != nil { return err @@ -269,6 +274,19 @@ func DeleteUser(ctx context.Context, u *user_model.User, purge bool) error { return nil } +func deleteUserUnlinkedAttachments(ctx context.Context, u *user_model.User) error { + attachments, err := repo_model.GetUnlinkedAttachmentsByUserID(ctx, u.ID) + if err != nil { + return fmt.Errorf("GetUnlinkedAttachmentsByUserID: %w", err) + } + for _, attach := range attachments { + if err := repo_model.DeleteAttachment(ctx, attach, true); err != nil { + return fmt.Errorf("DeleteAttachment ID[%d]: %w", attach.ID, err) + } + } + return nil +} + // DeleteInactiveUsers deletes all inactive users and their email addresses. func DeleteInactiveUsers(ctx context.Context, olderThan time.Duration) error { inactiveUsers, err := user_model.GetInactiveUsers(ctx, olderThan) diff --git a/services/user/user_test.go b/services/user/user_test.go index 25e8ee7b2fec1..4d8d448dcd57e 100644 --- a/services/user/user_test.go +++ b/services/user/user_test.go @@ -63,6 +63,24 @@ func TestDeleteUser(t *testing.T) { assert.Error(t, DeleteUser(t.Context(), org, false)) } +func TestDeleteUserUnlinkedAttachments(t *testing.T) { + t.Run("DeleteExisting", func(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 8}) + unittest.AssertExistsAndLoadBean(t, &repo_model.Attachment{ID: 10}) + + assert.NoError(t, deleteUserUnlinkedAttachments(t.Context(), user)) + unittest.AssertNotExistsBean(t, &repo_model.Attachment{ID: 10}) + }) + + t.Run("NoUnlinkedAttachments", func(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + + assert.NoError(t, deleteUserUnlinkedAttachments(t.Context(), user)) + }) +} + func TestPurgeUser(t *testing.T) { test := func(userID int64) { assert.NoError(t, unittest.PrepareTestDatabase()) From 8aa804086cdd12c289231d07087edb1b14693c43 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 13 Jan 2026 20:32:47 -0800 Subject: [PATCH 3/5] Fix lint --- models/repo/attachment_test.go | 2 +- routers/web/repo/attachment.go | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/models/repo/attachment_test.go b/models/repo/attachment_test.go index fdc48d3cdb4b0..07f4c587a7ab8 100644 --- a/models/repo/attachment_test.go +++ b/models/repo/attachment_test.go @@ -115,5 +115,5 @@ func TestGetUnlinkedAttachmentsByUserID(t *testing.T) { attachments, err = repo_model.GetUnlinkedAttachmentsByUserID(t.Context(), 1) assert.NoError(t, err) - assert.Len(t, attachments, 0) + assert.Empty(t, attachments) } diff --git a/routers/web/repo/attachment.go b/routers/web/repo/attachment.go index 549835bd868a4..7be6b0ba9a997 100644 --- a/routers/web/repo/attachment.go +++ b/routers/web/repo/attachment.go @@ -150,20 +150,22 @@ func ServeAttachment(ctx *context.Context, uuid string) { return } } else { // If we have the linked type, we need to check access - repo := ctx.Repo.Repository - if repo == nil { - repo, err = repo_model.GetRepositoryByID(ctx, attach.RepoID) + var perm access_model.Permission + if ctx.Repo.Repository == nil { + repo, err := repo_model.GetRepositoryByID(ctx, attach.RepoID) if err != nil { ctx.ServerError("GetRepositoryByID", err) return } + perm, err = access_model.GetUserRepoPermission(ctx, repo, ctx.Doer) + if err != nil { + ctx.ServerError("GetUserRepoPermission", err) + return + } + } else { + perm = ctx.Repo.Permission } - perm, err := access_model.GetUserRepoPermission(ctx, repo, ctx.Doer) - if err != nil { - ctx.ServerError("GetUserRepoPermission", err) - return - } if !perm.CanRead(unitType) { ctx.NotFound(nil) return From b829fbc0563ac8e37d4a6e11917755d4528dfcfc Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 13 Jan 2026 20:46:14 -0800 Subject: [PATCH 4/5] Rename functions --- routers/web/repo/attachment.go | 12 ++++++------ services/repository/repository.go | 6 +++--- services/repository/repository_test.go | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/routers/web/repo/attachment.go b/routers/web/repo/attachment.go index 7be6b0ba9a997..0f4037b05c2a7 100644 --- a/routers/web/repo/attachment.go +++ b/routers/web/repo/attachment.go @@ -125,7 +125,7 @@ func ServeAttachment(ctx *context.Context, uuid string) { attach, err := repo_model.GetAttachmentByUUID(ctx, uuid) if err != nil { if repo_model.IsErrAttachmentNotExist(err) { - ctx.NotFound(nil) + ctx.HTTPError(http.StatusNotFound) } else { ctx.ServerError("GetAttachmentByUUID", err) } @@ -134,19 +134,19 @@ func ServeAttachment(ctx *context.Context, uuid string) { // prevent visiting attachment from other repository directly if ctx.Repo.Repository != nil && ctx.Repo.Repository.ID != attach.RepoID { - ctx.NotFound(nil) + ctx.HTTPError(http.StatusNotFound) return } - unitType, err := repo_service.AttachLinkedType(ctx, attach) + unitType, err := repo_service.GetAttachmentLinkedType(ctx, attach) if err != nil { - ctx.ServerError("AttachLinkedType", err) + ctx.ServerError("GetAttachmentLinkedType", err) return } if unitType == -1 { // unlinked attachment can only be accessed by the uploader if !(ctx.IsSigned && attach.UploaderID == ctx.Doer.ID) { // We block if not the uploader - ctx.NotFound(nil) + ctx.HTTPError(http.StatusNotFound) return } } else { // If we have the linked type, we need to check access @@ -167,7 +167,7 @@ func ServeAttachment(ctx *context.Context, uuid string) { } if !perm.CanRead(unitType) { - ctx.NotFound(nil) + ctx.HTTPError(http.StatusNotFound) return } } diff --git a/services/repository/repository.go b/services/repository/repository.go index 0966bb8c26ad9..a38c6eee7a373 100644 --- a/services/repository/repository.go +++ b/services/repository/repository.go @@ -217,8 +217,8 @@ func MakeRepoPrivate(ctx context.Context, repo *repo_model.Repository) (err erro }) } -// AttachLinkedType returns the linked type of attachment if any -func AttachLinkedType(ctx context.Context, a *repo_model.Attachment) (unit.Type, error) { +// GetAttachmentLinkedType returns the linked type of attachment if any +func GetAttachmentLinkedType(ctx context.Context, a *repo_model.Attachment) (unit.Type, error) { if a.IssueID != 0 { iss, err := issues_model.GetIssueByID(ctx, a.IssueID) if err != nil { @@ -238,7 +238,7 @@ func AttachLinkedType(ctx context.Context, a *repo_model.Attachment) (unit.Type, } return unit.TypeReleases, nil } - return -1, nil + return unit.TypeInvalid, nil } // CheckDaemonExportOK creates/removes git-daemon-export-ok for git-daemon... diff --git a/services/repository/repository_test.go b/services/repository/repository_test.go index b63a97c1c2f84..88db240eea57a 100644 --- a/services/repository/repository_test.go +++ b/services/repository/repository_test.go @@ -25,13 +25,13 @@ func TestAttachLinkedType(t *testing.T) { {"LinkedIssue", 1, unit.TypeIssues}, {"LinkedComment", 3, unit.TypePullRequests}, {"LinkedRelease", 9, unit.TypeReleases}, - {"Notlinked", 10, -1}, + {"Notlinked", 10, unit.TypeInvalid}, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { attach, err := repo_model.GetAttachmentByID(t.Context(), tc.attachID) assert.NoError(t, err) - unitType, err := AttachLinkedType(t.Context(), attach) + unitType, err := GetAttachmentLinkedType(t.Context(), attach) assert.NoError(t, err) assert.Equal(t, tc.expectedUnitType, unitType) }) From 38dc9dfd2d367305f3a645124b3650f8e4eed522 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 13 Jan 2026 22:21:28 -0800 Subject: [PATCH 5/5] Fix bug --- routers/web/repo/attachment.go | 2 +- services/repository/repository.go | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/routers/web/repo/attachment.go b/routers/web/repo/attachment.go index 0f4037b05c2a7..c8501792cee7d 100644 --- a/routers/web/repo/attachment.go +++ b/routers/web/repo/attachment.go @@ -144,7 +144,7 @@ func ServeAttachment(ctx *context.Context, uuid string) { return } - if unitType == -1 { // unlinked attachment can only be accessed by the uploader + if unitType == unit.TypeInvalid { // unlinked attachment can only be accessed by the uploader if !(ctx.IsSigned && attach.UploaderID == ctx.Doer.ID) { // We block if not the uploader ctx.HTTPError(http.StatusNotFound) return diff --git a/services/repository/repository.go b/services/repository/repository.go index a38c6eee7a373..8a30592a8fce3 100644 --- a/services/repository/repository.go +++ b/services/repository/repository.go @@ -233,10 +233,7 @@ func GetAttachmentLinkedType(ctx context.Context, a *repo_model.Attachment) (uni if a.ReleaseID != 0 { _, err := repo_model.GetReleaseByID(ctx, a.ReleaseID) - if err != nil { - return unit.TypeReleases, err - } - return unit.TypeReleases, nil + return unit.TypeReleases, err } return unit.TypeInvalid, nil }