Skip to content

Commit 0690cb0

Browse files
authored
Fix missing signature key error when pulling Docker images with SERVE_DIRECT enabled (#32365)
Fix #28121 I did some tests and found that the `missing signature key` error is caused by an incorrect `Content-Type` header. Gitea correctly sets the `Content-Type` header when serving files. https://github.com/go-gitea/gitea/blob/348d1d0f322ca57c459acd902f54821d687ca804/routers/api/packages/container/container.go#L712-L717 However, when `SERVE_DIRECT` is enabled, the `Content-Type` header may be set to an incorrect value by the storage service. To fix this issue, we can use query parameters to override response header values. https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html <img width="600px" src="https://github.com/user-attachments/assets/f2ff90f0-f1df-46f9-9680-b8120222c555" /> In this PR, I introduced a new parameter to the `URL` method to support additional parameters. ``` URL(path, name string, reqParams url.Values) (*url.URL, error) ``` --- Most S3-like services support specifying the content type when storing objects. However, Gitea always use `application/octet-stream`. Therefore, I believe we also need to improve the `Save` method to support storing objects with the correct content type. https://github.com/go-gitea/gitea/blob/b7fb20e73e63b8edc9b90c52073e248bef428fcc/modules/storage/minio.go#L214-L221
1 parent 8107823 commit 0690cb0

File tree

19 files changed

+30
-24
lines changed

19 files changed

+30
-24
lines changed

modules/packages/content_store.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ func (s *ContentStore) ShouldServeDirect() bool {
3737
return setting.Packages.Storage.ServeDirect()
3838
}
3939

40-
func (s *ContentStore) GetServeDirectURL(key BlobHash256Key, filename string) (*url.URL, error) {
41-
return s.store.URL(KeyToRelativePath(key), filename)
40+
func (s *ContentStore) GetServeDirectURL(key BlobHash256Key, filename string, reqParams url.Values) (*url.URL, error) {
41+
return s.store.URL(KeyToRelativePath(key), filename, reqParams)
4242
}
4343

4444
// FIXME: Workaround to be removed in v1.20

modules/storage/azureblob.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ func (a *AzureBlobStorage) Delete(path string) error {
247247
}
248248

249249
// URL gets the redirect URL to a file. The presigned link is valid for 5 minutes.
250-
func (a *AzureBlobStorage) URL(path, name string) (*url.URL, error) {
250+
func (a *AzureBlobStorage) URL(path, name string, reqParams url.Values) (*url.URL, error) {
251251
blobClient := a.getBlobClient(path)
252252

253253
startTime := time.Now()

modules/storage/helper.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ func (s discardStorage) Delete(_ string) error {
3030
return fmt.Errorf("%s", s)
3131
}
3232

33-
func (s discardStorage) URL(_, _ string) (*url.URL, error) {
33+
func (s discardStorage) URL(_, _ string, _ url.Values) (*url.URL, error) {
3434
return nil, fmt.Errorf("%s", s)
3535
}
3636

modules/storage/helper_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ func Test_discardStorage(t *testing.T) {
3737
assert.Error(t, err, string(tt))
3838
}
3939
{
40-
got, err := tt.URL("path", "name")
40+
got, err := tt.URL("path", "name", nil)
4141
assert.Nil(t, got)
4242
assert.Errorf(t, err, string(tt))
4343
}

modules/storage/local.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ func (l *LocalStorage) Delete(path string) error {
114114
}
115115

116116
// URL gets the redirect URL to a file
117-
func (l *LocalStorage) URL(path, name string) (*url.URL, error) {
117+
func (l *LocalStorage) URL(path, name string, reqParams url.Values) (*url.URL, error) {
118118
return nil, ErrURLNotSupported
119119
}
120120

modules/storage/minio.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -276,8 +276,12 @@ func (m *MinioStorage) Delete(path string) error {
276276
}
277277

278278
// URL gets the redirect URL to a file. The presigned link is valid for 5 minutes.
279-
func (m *MinioStorage) URL(path, name string) (*url.URL, error) {
280-
reqParams := make(url.Values)
279+
func (m *MinioStorage) URL(path, name string, serveDirectReqParams url.Values) (*url.URL, error) {
280+
// copy serveDirectReqParams
281+
reqParams, err := url.ParseQuery(serveDirectReqParams.Encode())
282+
if err != nil {
283+
return nil, err
284+
}
281285
// TODO it may be good to embed images with 'inline' like ServeData does, but we don't want to have to read the file, do we?
282286
reqParams.Set("response-content-disposition", "attachment; filename=\""+quoteEscaper.Replace(name)+"\"")
283287
u, err := m.client.PresignedGetObject(m.ctx, m.bucket, m.buildMinioPath(path), 5*time.Minute, reqParams)

modules/storage/storage.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ type ObjectStorage interface {
6363
Save(path string, r io.Reader, size int64) (int64, error)
6464
Stat(path string) (os.FileInfo, error)
6565
Delete(path string) error
66-
URL(path, name string) (*url.URL, error)
66+
URL(path, name string, reqParams url.Values) (*url.URL, error)
6767
IterateObjects(path string, iterator func(path string, obj Object) error) error
6868
}
6969

routers/api/actions/artifacts.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,7 @@ func (ar artifactRoutes) getDownloadArtifactURL(ctx *ArtifactContext) {
425425
for _, artifact := range artifacts {
426426
var downloadURL string
427427
if setting.Actions.ArtifactStorage.ServeDirect() {
428-
u, err := ar.fs.URL(artifact.StoragePath, artifact.ArtifactName)
428+
u, err := ar.fs.URL(artifact.StoragePath, artifact.ArtifactName, nil)
429429
if err != nil && !errors.Is(err, storage.ErrURLNotSupported) {
430430
log.Error("Error getting serve direct url: %v", err)
431431
}

routers/api/actions/artifactsv4.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,7 @@ func (r *artifactV4Routes) getSignedArtifactURL(ctx *ArtifactContext) {
517517
respData := GetSignedArtifactURLResponse{}
518518

519519
if setting.Actions.ArtifactStorage.ServeDirect() {
520-
u, err := storage.ActionsArtifacts.URL(artifact.StoragePath, artifact.ArtifactPath)
520+
u, err := storage.ActionsArtifacts.URL(artifact.StoragePath, artifact.ArtifactPath, nil)
521521
if u != nil && err == nil {
522522
respData.SignedUrl = u.String()
523523
}

routers/api/packages/container/container.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -703,7 +703,9 @@ func DeleteManifest(ctx *context.Context) {
703703
}
704704

705705
func serveBlob(ctx *context.Context, pfd *packages_model.PackageFileDescriptor) {
706-
s, u, _, err := packages_service.GetPackageBlobStream(ctx, pfd.File, pfd.Blob)
706+
serveDirectReqParams := make(url.Values)
707+
serveDirectReqParams.Set("response-content-type", pfd.Properties.GetByName(container_module.PropertyMediaType))
708+
s, u, _, err := packages_service.GetPackageBlobStream(ctx, pfd.File, pfd.Blob, serveDirectReqParams)
707709
if err != nil {
708710
apiError(ctx, http.StatusInternalServerError, err)
709711
return

0 commit comments

Comments
 (0)