diff --git a/models/repo/release.go b/models/repo/release.go index bc136c6a84..e2010c8a38 100644 --- a/models/repo/release.go +++ b/models/repo/release.go @@ -93,9 +93,9 @@ func init() { db.RegisterModel(new(Release)) } -// legacyAttachmentMissingRepoIDCutoff marks the date when repo_id started to be written during uploads +// 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 +const LegacyAttachmentMissingRepoIDCutoff timeutil.TimeStamp = 1768521600 func (r *Release) LoadRepo(ctx context.Context) (err error) { if r.Repo != nil { @@ -190,7 +190,7 @@ func AddReleaseAttachments(ctx context.Context, releaseID int64, attachmentUUIDs } for i := range attachments { - if attachments[i].RepoID == 0 && attachments[i].CreatedUnix < legacyAttachmentMissingRepoIDCutoff { + 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) diff --git a/models/repo/release_test.go b/models/repo/release_test.go index abf50b1edb..2a09ffb36d 100644 --- a/models/repo/release_test.go +++ b/models/repo/release_test.go @@ -77,7 +77,7 @@ func TestAddReleaseAttachmentsRejectsRecentZeroRepoID(t *testing.T) { ReleaseID: 0, CommentID: 0, Name: "recent-zero", - CreatedUnix: legacyAttachmentMissingRepoIDCutoff + 1, + CreatedUnix: LegacyAttachmentMissingRepoIDCutoff + 1, } assert.NoError(t, db.Insert(t.Context(), attachment)) diff --git a/routers/web/repo/attachment.go b/routers/web/repo/attachment.go index c8501792ce..ae52eb2ffa 100644 --- a/routers/web/repo/attachment.go +++ b/routers/web/repo/attachment.go @@ -133,14 +133,15 @@ 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 { + // The check will be ignored before this code merged. + if attach.CreatedUnix > repo_model.LegacyAttachmentMissingRepoIDCutoff && ctx.Repo.Repository != nil && ctx.Repo.Repository.ID != attach.RepoID { ctx.HTTPError(http.StatusNotFound) return } - unitType, err := repo_service.GetAttachmentLinkedType(ctx, attach) + unitType, repoID, err := repo_service.GetAttachmentLinkedTypeAndRepoID(ctx, attach) if err != nil { - ctx.ServerError("GetAttachmentLinkedType", err) + ctx.ServerError("GetAttachmentLinkedTypeAndRepoID", err) return } @@ -152,7 +153,7 @@ func ServeAttachment(ctx *context.Context, uuid string) { } else { // If we have the linked type, we need to check access var perm access_model.Permission if ctx.Repo.Repository == nil { - repo, err := repo_model.GetRepositoryByID(ctx, attach.RepoID) + repo, err := repo_model.GetRepositoryByID(ctx, repoID) if err != nil { ctx.ServerError("GetRepositoryByID", err) return diff --git a/services/repository/repository.go b/services/repository/repository.go index 318ab423e5..ae64f0116a 100644 --- a/services/repository/repository.go +++ b/services/repository/repository.go @@ -221,25 +221,28 @@ func MakeRepoPrivate(ctx context.Context, repo *repo_model.Repository) (err erro }) } -// GetAttachmentLinkedType returns the linked type of attachment if any -func GetAttachmentLinkedType(ctx context.Context, a *repo_model.Attachment) (unit.Type, error) { +// GetAttachmentLinkedTypeAndRepoID returns the linked type and repository id of attachment if any +func GetAttachmentLinkedTypeAndRepoID(ctx context.Context, a *repo_model.Attachment) (unit.Type, int64, error) { if a.IssueID != 0 { iss, err := issues_model.GetIssueByID(ctx, a.IssueID) if err != nil { - return unit.TypeIssues, err + return unit.TypeIssues, 0, err } unitType := unit.TypeIssues if iss.IsPull { unitType = unit.TypePullRequests } - return unitType, nil + return unitType, iss.RepoID, nil } if a.ReleaseID != 0 { - _, err := repo_model.GetReleaseByID(ctx, a.ReleaseID) - return unit.TypeReleases, err + rel, err := repo_model.GetReleaseByID(ctx, a.ReleaseID) + if err != nil { + return unit.TypeReleases, 0, err + } + return unit.TypeReleases, rel.RepoID, nil } - return unit.TypeInvalid, nil + return unit.TypeInvalid, 0, 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 b3447ae166..395138b5e4 100644 --- a/services/repository/repository_test.go +++ b/services/repository/repository_test.go @@ -16,25 +16,27 @@ import ( "github.com/stretchr/testify/require" ) -func TestAttachLinkedType(t *testing.T) { +func TestAttachLinkedTypeAndRepoID(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) testCases := []struct { name string attachID int64 expectedUnitType unit.Type + expectedRepoID uint64 }{ - {"LinkedIssue", 1, unit.TypeIssues}, - {"LinkedComment", 3, unit.TypePullRequests}, - {"LinkedRelease", 9, unit.TypeReleases}, - {"Notlinked", 10, unit.TypeInvalid}, + {"LinkedIssue", 1, unit.TypeIssues, 1}, + {"LinkedComment", 3, unit.TypePullRequests, 1}, + {"LinkedRelease", 9, unit.TypeReleases, 1}, + {"Notlinked", 10, unit.TypeInvalid, 0}, } 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 := GetAttachmentLinkedType(t.Context(), attach) + unitType, repoID, err := GetAttachmentLinkedTypeAndRepoID(t.Context(), attach) assert.NoError(t, err) assert.Equal(t, tc.expectedUnitType, unitType) + assert.Equal(t, tc.expectedRepoID, repoID) }) } }