Commit 6fba18f6 authored by Alessio Caiazza's avatar Alessio Caiazza

Artifacts and Uploads must allow Objects Storage only requests

parent 9eaf0fe2
...@@ -63,7 +63,12 @@ func TestUploadHandlerSendingToExternalStorage(t *testing.T) { ...@@ -63,7 +63,12 @@ func TestUploadHandlerSendingToExternalStorage(t *testing.T) {
defer os.RemoveAll(tempPath) defer os.RemoveAll(tempPath)
archiveData, md5 := createTestZipArchive(t) archiveData, md5 := createTestZipArchive(t)
contentBuffer, contentType := createTestMultipartForm(t, archiveData) archiveFile, err := ioutil.TempFile("", "artifact.zip")
require.NoError(t, err)
defer os.Remove(archiveFile.Name())
_, err = archiveFile.Write(archiveData)
require.NoError(t, err)
archiveFile.Close()
storeServerCalled := 0 storeServerCalled := 0
storeServerMux := http.NewServeMux() storeServerMux := http.NewServeMux()
...@@ -78,6 +83,9 @@ func TestUploadHandlerSendingToExternalStorage(t *testing.T) { ...@@ -78,6 +83,9 @@ func TestUploadHandlerSendingToExternalStorage(t *testing.T) {
w.Header().Set("ETag", md5) w.Header().Set("ETag", md5)
w.WriteHeader(200) w.WriteHeader(200)
}) })
storeServerMux.HandleFunc("/store-id", func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, archiveFile.Name())
})
responseProcessorCalled := 0 responseProcessorCalled := 0
responseProcessor := func(w http.ResponseWriter, r *http.Request) { responseProcessor := func(w http.ResponseWriter, r *http.Request) {
...@@ -90,22 +98,48 @@ func TestUploadHandlerSendingToExternalStorage(t *testing.T) { ...@@ -90,22 +98,48 @@ func TestUploadHandlerSendingToExternalStorage(t *testing.T) {
storeServer := httptest.NewServer(storeServerMux) storeServer := httptest.NewServer(storeServerMux)
defer storeServer.Close() defer storeServer.Close()
authResponse := api.Response{ tests := []struct {
name string
preauth api.Response
}{
{
name: "ObjectStore Upload",
preauth: api.Response{
RemoteObject: api.RemoteObject{
StoreURL: storeServer.URL + "/url/put",
ID: "store-id",
GetURL: storeServer.URL + "/store-id",
},
},
},
{
name: "ObjectStore and FileStore Upload",
preauth: api.Response{
TempPath: tempPath, TempPath: tempPath,
RemoteObject: api.RemoteObject{ RemoteObject: api.RemoteObject{
StoreURL: storeServer.URL + "/url/put", StoreURL: storeServer.URL + "/url/put",
ID: "store-id", ID: "store-id",
GetURL: storeServer.URL + "/store-id", GetURL: storeServer.URL + "/store-id",
}, },
},
},
} }
ts := testArtifactsUploadServer(t, authResponse, responseProcessor) for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
storeServerCalled = 0
responseProcessorCalled = 0
ts := testArtifactsUploadServer(t, test.preauth, responseProcessor)
defer ts.Close() defer ts.Close()
contentBuffer, contentType := createTestMultipartForm(t, archiveData)
response := testUploadArtifacts(contentType, &contentBuffer, t, ts) response := testUploadArtifacts(contentType, &contentBuffer, t, ts)
testhelper.AssertResponseCode(t, response, 200) testhelper.AssertResponseCode(t, response, 200)
assert.Equal(t, 1, storeServerCalled, "store should be called only once") assert.Equal(t, 1, storeServerCalled, "store should be called only once")
assert.Equal(t, 1, responseProcessorCalled, "response processor should be called only once") assert.Equal(t, 1, responseProcessorCalled, "response processor should be called only once")
})
}
} }
func TestUploadHandlerSendingToExternalStorageAndStorageServerUnreachable(t *testing.T) { func TestUploadHandlerSendingToExternalStorageAndStorageServerUnreachable(t *testing.T) {
......
...@@ -31,6 +31,9 @@ func (a *artifactsUploadProcessor) generateMetadataFromZip(ctx context.Context, ...@@ -31,6 +31,9 @@ func (a *artifactsUploadProcessor) generateMetadataFromZip(ctx context.Context,
LocalTempPath: a.opts.LocalTempPath, LocalTempPath: a.opts.LocalTempPath,
TempFilePrefix: "metadata.gz", TempFilePrefix: "metadata.gz",
} }
if metaOpts.LocalTempPath == "" {
metaOpts.LocalTempPath = os.TempDir()
}
fileName := file.LocalPath fileName := file.LocalPath
if fileName == "" { if fileName == "" {
...@@ -115,11 +118,6 @@ func (a *artifactsUploadProcessor) Name() string { ...@@ -115,11 +118,6 @@ func (a *artifactsUploadProcessor) Name() string {
func UploadArtifacts(myAPI *api.API, h http.Handler) http.Handler { func UploadArtifacts(myAPI *api.API, h http.Handler) http.Handler {
return myAPI.PreAuthorizeHandler(func(w http.ResponseWriter, r *http.Request, a *api.Response) { return myAPI.PreAuthorizeHandler(func(w http.ResponseWriter, r *http.Request, a *api.Response) {
if a.TempPath == "" {
helper.Fail500(w, r, fmt.Errorf("UploadArtifacts: TempPath is empty"))
return
}
mg := &artifactsUploadProcessor{opts: filestore.GetOpts(a)} mg := &artifactsUploadProcessor{opts: filestore.GetOpts(a)}
upload.HandleFileUploads(w, r, h, a, mg) upload.HandleFileUploads(w, r, h, a, mg)
......
...@@ -16,6 +16,7 @@ import ( ...@@ -16,6 +16,7 @@ import (
"gitlab.com/gitlab-org/gitlab-workhorse/internal/api" "gitlab.com/gitlab-org/gitlab-workhorse/internal/api"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/badgateway" "gitlab.com/gitlab-org/gitlab-workhorse/internal/badgateway"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/filestore"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/helper" "gitlab.com/gitlab-org/gitlab-workhorse/internal/helper"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/proxy" "gitlab.com/gitlab-org/gitlab-workhorse/internal/proxy"
"gitlab.com/gitlab-org/gitlab-workhorse/internal/testhelper" "gitlab.com/gitlab-org/gitlab-workhorse/internal/testhelper"
...@@ -38,23 +39,33 @@ func testArtifactsUploadServer(t *testing.T, authResponse api.Response, bodyProc ...@@ -38,23 +39,33 @@ func testArtifactsUploadServer(t *testing.T, authResponse api.Response, bodyProc
w.Write(data) w.Write(data)
}) })
mux.HandleFunc("/url/path", func(w http.ResponseWriter, r *http.Request) { mux.HandleFunc("/url/path", func(w http.ResponseWriter, r *http.Request) {
opts := filestore.GetOpts(&authResponse)
if r.Method != "POST" { if r.Method != "POST" {
t.Fatal("Expected POST request") t.Fatal("Expected POST request")
} }
if opts.IsLocal() {
if r.FormValue("file.path") == "" { if r.FormValue("file.path") == "" {
w.WriteHeader(501) w.WriteHeader(501)
return return
} }
if r.FormValue("metadata.path") == "" {
w.WriteHeader(502)
return
}
_, err := ioutil.ReadFile(r.FormValue("file.path")) _, err := ioutil.ReadFile(r.FormValue("file.path"))
if err != nil { if err != nil {
w.WriteHeader(404) w.WriteHeader(404)
return return
} }
}
if opts.IsRemote() && r.FormValue("file.remote_url") == "" {
w.WriteHeader(501)
return
}
if r.FormValue("metadata.path") == "" {
w.WriteHeader(502)
return
}
metadata, err := ioutil.ReadFile(r.FormValue("metadata.path")) metadata, err := ioutil.ReadFile(r.FormValue("metadata.path"))
if err != nil { if err != nil {
......
...@@ -22,8 +22,9 @@ type MultipartFormProcessor interface { ...@@ -22,8 +22,9 @@ type MultipartFormProcessor interface {
} }
func HandleFileUploads(w http.ResponseWriter, r *http.Request, h http.Handler, preauth *api.Response, filter MultipartFormProcessor) { func HandleFileUploads(w http.ResponseWriter, r *http.Request, h http.Handler, preauth *api.Response, filter MultipartFormProcessor) {
if preauth.TempPath == "" { opts := filestore.GetOpts(preauth)
helper.Fail500(w, r, fmt.Errorf("handleFileUploads: tempPath empty")) if !opts.IsLocal() && !opts.IsRemote() {
helper.Fail500(w, r, fmt.Errorf("handleFileUploads: missing destination storage"))
return return
} }
......
...@@ -243,6 +243,29 @@ func TestUploadProcessingFile(t *testing.T) { ...@@ -243,6 +243,29 @@ func TestUploadProcessingFile(t *testing.T) {
fmt.Fprint(file, "test") fmt.Fprint(file, "test")
writer.Close() writer.Close()
tests := []struct {
name string
preauth api.Response
}{
{
name: "FileStore Upload",
preauth: api.Response{TempPath: tempPath},
},
{
name: "ObjectStore Upload",
preauth: api.Response{RemoteObject: api.RemoteObject{StoreURL: "http://example.com"}},
},
{
name: "ObjectStore and FileStore Upload",
preauth: api.Response{
TempPath: tempPath,
RemoteObject: api.RemoteObject{StoreURL: "http://example.com"},
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
httpRequest, err := http.NewRequest("PUT", "/url/path", &buffer) httpRequest, err := http.NewRequest("PUT", "/url/path", &buffer)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
...@@ -250,8 +273,11 @@ func TestUploadProcessingFile(t *testing.T) { ...@@ -250,8 +273,11 @@ func TestUploadProcessingFile(t *testing.T) {
httpRequest.Header.Set("Content-Type", writer.FormDataContentType()) httpRequest.Header.Set("Content-Type", writer.FormDataContentType())
response := httptest.NewRecorder() response := httptest.NewRecorder()
HandleFileUploads(response, httpRequest, nilHandler, &api.Response{TempPath: tempPath}, &testFormProcessor{}) HandleFileUploads(response, httpRequest, nilHandler, &test.preauth, &testFormProcessor{})
testhelper.AssertResponseCode(t, response, 500) testhelper.AssertResponseCode(t, response, 500)
})
}
} }
func TestInvalidFileNames(t *testing.T) { func TestInvalidFileNames(t *testing.T) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment