mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-31 10:56:10 +01:00 
			
		
		
		
	Add an immutable tarball link to archive download headers for Nix (#31139)
This allows `nix flake metadata` and nix in general to lock a *branch* tarball link in a manner that causes it to fetch the correct commit even if the branch is updated with a newer version. Co-authored-by: Jade Lovelace <software@lfcode.ca> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
		| @@ -319,6 +319,12 @@ func archiveDownload(ctx *context.APIContext) { | |||||||
| func download(ctx *context.APIContext, archiveName string, archiver *repo_model.RepoArchiver) { | func download(ctx *context.APIContext, archiveName string, archiver *repo_model.RepoArchiver) { | ||||||
| 	downloadName := ctx.Repo.Repository.Name + "-" + archiveName | 	downloadName := ctx.Repo.Repository.Name + "-" + archiveName | ||||||
|  |  | ||||||
|  | 	// Add nix format link header so tarballs lock correctly: | ||||||
|  | 	// https://github.com/nixos/nix/blob/56763ff918eb308db23080e560ed2ea3e00c80a7/doc/manual/src/protocols/tarball-fetcher.md | ||||||
|  | 	ctx.Resp.Header().Add("Link", fmt.Sprintf(`<%s/archive/%s.tar.gz?rev=%s>; rel="immutable"`, | ||||||
|  | 		ctx.Repo.Repository.APIURL(), | ||||||
|  | 		archiver.CommitID, archiver.CommitID)) | ||||||
|  |  | ||||||
| 	rPath := archiver.RelativePath() | 	rPath := archiver.RelativePath() | ||||||
| 	if setting.RepoArchive.Storage.MinioConfig.ServeDirect { | 	if setting.RepoArchive.Storage.MinioConfig.ServeDirect { | ||||||
| 		// If we have a signed url (S3, object storage), redirect to this directly. | 		// If we have a signed url (S3, object storage), redirect to this directly. | ||||||
|   | |||||||
| @@ -484,6 +484,12 @@ func Download(ctx *context.Context) { | |||||||
| func download(ctx *context.Context, archiveName string, archiver *repo_model.RepoArchiver) { | func download(ctx *context.Context, archiveName string, archiver *repo_model.RepoArchiver) { | ||||||
| 	downloadName := ctx.Repo.Repository.Name + "-" + archiveName | 	downloadName := ctx.Repo.Repository.Name + "-" + archiveName | ||||||
|  |  | ||||||
|  | 	// Add nix format link header so tarballs lock correctly: | ||||||
|  | 	// https://github.com/nixos/nix/blob/56763ff918eb308db23080e560ed2ea3e00c80a7/doc/manual/src/protocols/tarball-fetcher.md | ||||||
|  | 	ctx.Resp.Header().Add("Link", fmt.Sprintf(`<%s/archive/%s.tar.gz?rev=%s>; rel="immutable"`, | ||||||
|  | 		ctx.Repo.Repository.APIURL(), | ||||||
|  | 		archiver.CommitID, archiver.CommitID)) | ||||||
|  |  | ||||||
| 	rPath := archiver.RelativePath() | 	rPath := archiver.RelativePath() | ||||||
| 	if setting.RepoArchive.Storage.MinioConfig.ServeDirect { | 	if setting.RepoArchive.Storage.MinioConfig.ServeDirect { | ||||||
| 		// If we have a signed url (S3, object storage), redirect to this directly. | 		// If we have a signed url (S3, object storage), redirect to this directly. | ||||||
|   | |||||||
| @@ -8,6 +8,7 @@ import ( | |||||||
| 	"io" | 	"io" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"net/url" | 	"net/url" | ||||||
|  | 	"regexp" | ||||||
| 	"testing" | 	"testing" | ||||||
|  |  | ||||||
| 	auth_model "code.gitea.io/gitea/models/auth" | 	auth_model "code.gitea.io/gitea/models/auth" | ||||||
| @@ -39,6 +40,16 @@ func TestAPIDownloadArchive(t *testing.T) { | |||||||
| 	assert.NoError(t, err) | 	assert.NoError(t, err) | ||||||
| 	assert.Len(t, bs, 266) | 	assert.Len(t, bs, 266) | ||||||
|  |  | ||||||
|  | 	// Must return a link to a commit ID as the "immutable" archive link | ||||||
|  | 	linkHeaderRe := regexp.MustCompile(`^<(https?://.*/api/v1/repos/user2/repo1/archive/[a-f0-9]+\.tar\.gz.*)>; rel="immutable"$`) | ||||||
|  | 	m := linkHeaderRe.FindStringSubmatch(resp.Header().Get("Link")) | ||||||
|  | 	assert.NotEmpty(t, m[1]) | ||||||
|  | 	resp = MakeRequest(t, NewRequest(t, "GET", m[1]).AddTokenAuth(token), http.StatusOK) | ||||||
|  | 	bs2, err := io.ReadAll(resp.Body) | ||||||
|  | 	assert.NoError(t, err) | ||||||
|  | 	// The locked URL should give the same bytes as the non-locked one | ||||||
|  | 	assert.EqualValues(t, bs, bs2) | ||||||
|  |  | ||||||
| 	link, _ = url.Parse(fmt.Sprintf("/api/v1/repos/%s/%s/archive/master.bundle", user2.Name, repo.Name)) | 	link, _ = url.Parse(fmt.Sprintf("/api/v1/repos/%s/%s/archive/master.bundle", user2.Name, repo.Name)) | ||||||
| 	resp = MakeRequest(t, NewRequest(t, "GET", link.String()).AddTokenAuth(token), http.StatusOK) | 	resp = MakeRequest(t, NewRequest(t, "GET", link.String()).AddTokenAuth(token), http.StatusOK) | ||||||
| 	bs, err = io.ReadAll(resp.Body) | 	bs, err = io.ReadAll(resp.Body) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user