aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorChristopherHX <christopher.homberger@web.de>2024-09-22 13:01:09 +0200
committerGitHub <noreply@github.com>2024-09-22 14:01:09 +0300
commitb594cec2bda6f861effedb2e8e0a7ebba191c0e9 (patch)
tree770826f848c973d817a32f269d61420834ed640f /tests
parent74f2ee31248ccdd66218c89fafa7f91a1e1dc58a (diff)
downloadgitea-b594cec2bda6f861effedb2e8e0a7ebba191c0e9.tar.gz
gitea-b594cec2bda6f861effedb2e8e0a7ebba191c0e9.zip
Fix artifact v4 upload above 8MB (#31664)
Multiple chunks are uploaded with type "block" without using "appendBlock" and eventually out of order for bigger uploads. 8MB seems to be the chunk size This change parses the blockList uploaded after all blocks to get the final artifact size and order them correctly before calculating the sha256 checksum over all blocks Fixes #31354
Diffstat (limited to 'tests')
-rw-r--r--tests/integration/api_actions_artifact_v4_test.go130
1 files changed, 130 insertions, 0 deletions
diff --git a/tests/integration/api_actions_artifact_v4_test.go b/tests/integration/api_actions_artifact_v4_test.go
index f58f876849..ec0fbbfa60 100644
--- a/tests/integration/api_actions_artifact_v4_test.go
+++ b/tests/integration/api_actions_artifact_v4_test.go
@@ -7,12 +7,14 @@ import (
"bytes"
"crypto/sha256"
"encoding/hex"
+ "encoding/xml"
"io"
"net/http"
"strings"
"testing"
"time"
+ "code.gitea.io/gitea/modules/storage"
"code.gitea.io/gitea/routers/api/actions"
actions_service "code.gitea.io/gitea/services/actions"
"code.gitea.io/gitea/tests"
@@ -170,6 +172,134 @@ func TestActionsArtifactV4UploadSingleFileWithRetentionDays(t *testing.T) {
assert.True(t, finalizeResp.Ok)
}
+func TestActionsArtifactV4UploadSingleFileWithPotentialHarmfulBlockID(t *testing.T) {
+ defer tests.PrepareTestEnv(t)()
+
+ token, err := actions_service.CreateAuthorizationToken(48, 792, 193)
+ assert.NoError(t, err)
+
+ // acquire artifact upload url
+ req := NewRequestWithBody(t, "POST", "/twirp/github.actions.results.api.v1.ArtifactService/CreateArtifact", toProtoJSON(&actions.CreateArtifactRequest{
+ Version: 4,
+ Name: "artifactWithPotentialHarmfulBlockID",
+ WorkflowRunBackendId: "792",
+ WorkflowJobRunBackendId: "193",
+ })).AddTokenAuth(token)
+ resp := MakeRequest(t, req, http.StatusOK)
+ var uploadResp actions.CreateArtifactResponse
+ protojson.Unmarshal(resp.Body.Bytes(), &uploadResp)
+ assert.True(t, uploadResp.Ok)
+ assert.Contains(t, uploadResp.SignedUploadUrl, "/twirp/github.actions.results.api.v1.ArtifactService/UploadArtifact")
+
+ // get upload urls
+ idx := strings.Index(uploadResp.SignedUploadUrl, "/twirp/")
+ url := uploadResp.SignedUploadUrl[idx:] + "&comp=block&blockid=%2f..%2fmyfile"
+ blockListURL := uploadResp.SignedUploadUrl[idx:] + "&comp=blocklist"
+
+ // upload artifact chunk
+ body := strings.Repeat("A", 1024)
+ req = NewRequestWithBody(t, "PUT", url, strings.NewReader(body))
+ MakeRequest(t, req, http.StatusCreated)
+
+ // verify that the exploit didn't work
+ _, err = storage.Actions.Stat("myfile")
+ assert.Error(t, err)
+
+ // upload artifact blockList
+ blockList := &actions.BlockList{
+ Latest: []string{
+ "/../myfile",
+ },
+ }
+ rawBlockList, err := xml.Marshal(blockList)
+ assert.NoError(t, err)
+ req = NewRequestWithBody(t, "PUT", blockListURL, bytes.NewReader(rawBlockList))
+ MakeRequest(t, req, http.StatusCreated)
+
+ t.Logf("Create artifact confirm")
+
+ sha := sha256.Sum256([]byte(body))
+
+ // confirm artifact upload
+ req = NewRequestWithBody(t, "POST", "/twirp/github.actions.results.api.v1.ArtifactService/FinalizeArtifact", toProtoJSON(&actions.FinalizeArtifactRequest{
+ Name: "artifactWithPotentialHarmfulBlockID",
+ Size: 1024,
+ Hash: wrapperspb.String("sha256:" + hex.EncodeToString(sha[:])),
+ WorkflowRunBackendId: "792",
+ WorkflowJobRunBackendId: "193",
+ })).
+ AddTokenAuth(token)
+ resp = MakeRequest(t, req, http.StatusOK)
+ var finalizeResp actions.FinalizeArtifactResponse
+ protojson.Unmarshal(resp.Body.Bytes(), &finalizeResp)
+ assert.True(t, finalizeResp.Ok)
+}
+
+func TestActionsArtifactV4UploadSingleFileWithChunksOutOfOrder(t *testing.T) {
+ defer tests.PrepareTestEnv(t)()
+
+ token, err := actions_service.CreateAuthorizationToken(48, 792, 193)
+ assert.NoError(t, err)
+
+ // acquire artifact upload url
+ req := NewRequestWithBody(t, "POST", "/twirp/github.actions.results.api.v1.ArtifactService/CreateArtifact", toProtoJSON(&actions.CreateArtifactRequest{
+ Version: 4,
+ Name: "artifactWithChunksOutOfOrder",
+ WorkflowRunBackendId: "792",
+ WorkflowJobRunBackendId: "193",
+ })).AddTokenAuth(token)
+ resp := MakeRequest(t, req, http.StatusOK)
+ var uploadResp actions.CreateArtifactResponse
+ protojson.Unmarshal(resp.Body.Bytes(), &uploadResp)
+ assert.True(t, uploadResp.Ok)
+ assert.Contains(t, uploadResp.SignedUploadUrl, "/twirp/github.actions.results.api.v1.ArtifactService/UploadArtifact")
+
+ // get upload urls
+ idx := strings.Index(uploadResp.SignedUploadUrl, "/twirp/")
+ block1URL := uploadResp.SignedUploadUrl[idx:] + "&comp=block&blockid=block1"
+ block2URL := uploadResp.SignedUploadUrl[idx:] + "&comp=block&blockid=block2"
+ blockListURL := uploadResp.SignedUploadUrl[idx:] + "&comp=blocklist"
+
+ // upload artifact chunks
+ bodyb := strings.Repeat("B", 1024)
+ req = NewRequestWithBody(t, "PUT", block2URL, strings.NewReader(bodyb))
+ MakeRequest(t, req, http.StatusCreated)
+
+ bodya := strings.Repeat("A", 1024)
+ req = NewRequestWithBody(t, "PUT", block1URL, strings.NewReader(bodya))
+ MakeRequest(t, req, http.StatusCreated)
+
+ // upload artifact blockList
+ blockList := &actions.BlockList{
+ Latest: []string{
+ "block1",
+ "block2",
+ },
+ }
+ rawBlockList, err := xml.Marshal(blockList)
+ assert.NoError(t, err)
+ req = NewRequestWithBody(t, "PUT", blockListURL, bytes.NewReader(rawBlockList))
+ MakeRequest(t, req, http.StatusCreated)
+
+ t.Logf("Create artifact confirm")
+
+ sha := sha256.Sum256([]byte(bodya + bodyb))
+
+ // confirm artifact upload
+ req = NewRequestWithBody(t, "POST", "/twirp/github.actions.results.api.v1.ArtifactService/FinalizeArtifact", toProtoJSON(&actions.FinalizeArtifactRequest{
+ Name: "artifactWithChunksOutOfOrder",
+ Size: 2048,
+ Hash: wrapperspb.String("sha256:" + hex.EncodeToString(sha[:])),
+ WorkflowRunBackendId: "792",
+ WorkflowJobRunBackendId: "193",
+ })).
+ AddTokenAuth(token)
+ resp = MakeRequest(t, req, http.StatusOK)
+ var finalizeResp actions.FinalizeArtifactResponse
+ protojson.Unmarshal(resp.Body.Bytes(), &finalizeResp)
+ assert.True(t, finalizeResp.Ok)
+}
+
func TestActionsArtifactV4DownloadSingle(t *testing.T) {
defer tests.PrepareTestEnv(t)()