Skip to content

Commit f3f2a5e

Browse files
committed
fix: fall back to sha1 for an unusable DEFAULT_OBJECT_FORMAT
API creation and push-to-create now use DEFAULT_OBJECT_FORMAT, so an invalid value or sha256 on git older than 2.42 would break them or store a format that differs from the repo on disk. Keep the cargo index on sha1 since cargo clients can't fetch sha256 repos, and only probe the on-disk format during LFS garbage collection when an object needs checking. Assisted-by: Claude Code:claude-opus-5-5
1 parent 5cf5c05 commit f3f2a5e

11 files changed

Lines changed: 60 additions & 66 deletions

File tree

‎modules/git/archive_test.go‎

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,17 @@ import (
1717
func TestCreateBundle(t *testing.T) {
1818
setting.AppDataPath = t.TempDir()
1919

20-
for _, tc := range []struct{ repo, commit, version string }{
21-
{"repo1_bare", "ce064814f4a0d337b333e646ece456cd39fab612", "# v2 git bundle"},
22-
{"repo1_bare_sha256", "9433b2a62b964c17a4485ae180f45f595d3e69d31b786087775e28c6b6399df0", "# v3 git bundle"},
23-
} {
24-
buf := &bytes.Buffer{}
25-
require.NoError(t, CreateBundle(t.Context(), mockRepository(tc.repo), tc.commit, buf))
26-
27-
header, _, ok := strings.Cut(buf.String(), "\n\n")
28-
require.True(t, ok)
29-
assert.Equal(t, tc.version, strings.Split(header, "\n")[0])
30-
// without a refs/heads/* ref and a HEAD, a clone of the bundle has no branch and no checkout
31-
assert.Contains(t, header, tc.commit+" refs/heads/bundle")
32-
assert.Contains(t, header, tc.commit+" HEAD")
33-
}
20+
buf := &bytes.Buffer{}
21+
require.NoError(t, CreateBundle(t.Context(), mockRepository("repo1_bare"), "ce064814f4a0d337b333e646ece456cd39fab612", buf))
22+
23+
header, _, ok := strings.Cut(buf.String(), "\n\n")
24+
require.True(t, ok)
25+
assert.Equal(t, "# v2 git bundle", strings.Split(header, "\n")[0])
26+
// without a refs/heads/* ref and a HEAD, a clone of the bundle has no branch and no checkout
27+
assert.Contains(t, header, "ce064814f4a0d337b333e646ece456cd39fab612 refs/heads/bundle")
28+
assert.Contains(t, header, "ce064814f4a0d337b333e646ece456cd39fab612 HEAD")
29+
30+
buf.Reset()
31+
require.NoError(t, CreateBundle(t.Context(), mockRepository("repo1_bare_sha256"), "9433b2a62b964c17a4485ae180f45f595d3e69d31b786087775e28c6b6399df0", buf))
32+
assert.True(t, strings.HasPrefix(buf.String(), "# v3 git bundle\n@object-format=sha256\n"))
3433
}

‎modules/structs/hook.go‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ type PayloadUser struct {
108108

109109
// PayloadCommit represents a commit
110110
type PayloadCommit struct {
111-
// hash of the commit
111+
// sha1 hash of the commit
112112
ID string `json:"id"`
113113
// The commit message
114114
Message string `json:"message"`

‎routers/api/v1/repo/hash_algorithm.go‎

Lines changed: 0 additions & 37 deletions
This file was deleted.

‎routers/api/v1/repo/repo.go‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1311,3 +1311,29 @@ func ListRepoActivityFeeds(ctx *context.APIContext) {
13111311

13121312
ctx.JSON(http.StatusOK, convert.ToActivities(ctx, feeds, ctx.Doer))
13131313
}
1314+
1315+
func GetHashAlgorithm(ctx *context.APIContext) {
1316+
// swagger:operation GET /repos/{owner}/{repo}/hash-algorithm repository repoGetHashAlgorithm
1317+
// ---
1318+
// summary: Get the hash algorithm used to store repository objects
1319+
// produces:
1320+
// - application/json
1321+
// parameters:
1322+
// - name: owner
1323+
// in: path
1324+
// description: owner of the repo
1325+
// type: string
1326+
// required: true
1327+
// - name: repo
1328+
// in: path
1329+
// description: name of the repo
1330+
// type: string
1331+
// required: true
1332+
// responses:
1333+
// "200":
1334+
// "$ref": "#/responses/RepoHashAlgorithm"
1335+
// "404":
1336+
// "$ref": "#/responses/notFound"
1337+
1338+
ctx.JSON(http.StatusOK, api.RepoHashAlgorithm{HashAlgorithm: api.ObjectFormatName(ctx.Repo.Repository.ObjectFormatName)})
1339+
}

‎routers/init.go‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,10 @@ func InitWebInstalled(ctx context.Context) {
122122
translation.InitLocales(ctx)
123123

124124
setting.LoadSettings()
125+
if !git.IsValidObjectFormat(setting.Repository.DefaultObjectFormat) {
126+
log.Warn("[repository] DEFAULT_OBJECT_FORMAT %q is not supported, using sha1", setting.Repository.DefaultObjectFormat)
127+
setting.Repository.DefaultObjectFormat = git.Sha1ObjectFormat.Name()
128+
}
125129
mustInit(storage.Init)
126130

127131
mailer.NewContext(ctx)

‎services/packages/cargo/index.go‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,8 @@ func getOrCreateIndexRepository(ctx context.Context, doer, owner *user_model.Use
212212
if err != nil {
213213
if errors.Is(err, util.ErrNotExist) {
214214
repo, err = repo_service.CreateRepositoryDirectly(ctx, doer, owner, repo_service.CreateRepoOptions{
215-
Name: IndexRepositoryName,
215+
Name: IndexRepositoryName,
216+
ObjectFormatName: git.Sha1ObjectFormat.Name(), // cargo clients can't fetch sha256 repos
216217
}, true)
217218
if err != nil {
218219
return nil, fmt.Errorf("CreateRepository: %w", err)

‎services/repository/lfs.go‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,16 +82,16 @@ func GarbageCollectLFSMetaObjectsForRepo(ctx context.Context, repo *repo_model.R
8282

8383
store := lfs.NewContentStore()
8484
errStop := errors.New("STOPERR")
85-
objectFormat, err := gitRepo.GetObjectFormat(ctx) // on-disk format, the stored one can disagree with it
86-
if err != nil {
87-
return err
88-
}
8985

9086
err = git_model.IterateLFSMetaObjectsForRepo(ctx, repo.ID, func(ctx context.Context, metaObject *git_model.LFSMetaObject, count int64) error {
9187
if opts.NumberToCheckPerRepo > 0 && total > opts.NumberToCheckPerRepo {
9288
return errStop
9389
}
9490
total++
91+
objectFormat, err := gitRepo.GetObjectFormat(ctx) // on-disk format, the stored one can disagree with it
92+
if err != nil {
93+
return err
94+
}
9595
pointerSha := git.ComputeBlobHash(objectFormat, []byte(metaObject.Pointer.StringContent()))
9696

9797
if gitRepo.IsObjectExist(ctx, pointerSha.String()) {

‎templates/swagger/v1-openapi3.generated.json‎

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎templates/swagger/v1-swagger.generated.json‎

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎tests/integration/api_helper_for_declarative_test.go‎

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,12 @@ import (
2424
)
2525

2626
type APITestContext struct {
27-
Reponame string
28-
Session *TestSession
29-
Token string
30-
Username string
31-
ExpectedCode int
27+
Reponame string
28+
Session *TestSession
29+
Token string
30+
Username string
31+
ExpectedCode int
32+
3233
ObjectFormatName api.ObjectFormatName
3334
}
3435

0 commit comments

Comments
 (0)