Skip to content

Commit

Permalink
fix: update artifact server to address GHSL-2023-004 (#1565)
Browse files Browse the repository at this point in the history
  • Loading branch information
cplee authored Jan 16, 2023
1 parent efb12b7 commit 63ae215
Show file tree
Hide file tree
Showing 4 changed files with 202 additions and 73 deletions.
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"go.lintTool": "golangci-lint",
"go.lintFlags": ["--fix"],
"go.testTimeout": "300s",
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
Expand Down
82 changes: 45 additions & 37 deletions pkg/artifacts/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"io/fs"
"net/http"
"os"
"path"
"path/filepath"
"strings"
"time"
Expand Down Expand Up @@ -46,28 +45,34 @@ type ResponseMessage struct {
Message string `json:"message"`
}

type MkdirFS interface {
fs.FS
MkdirAll(path string, perm fs.FileMode) error
Open(name string) (fs.File, error)
OpenAtEnd(name string) (fs.File, error)
type WritableFile interface {
io.WriteCloser
}

type MkdirFsImpl struct {
dir string
fs.FS
type WriteFS interface {
OpenWritable(name string) (WritableFile, error)
OpenAppendable(name string) (WritableFile, error)
}

func (fsys MkdirFsImpl) MkdirAll(path string, perm fs.FileMode) error {
return os.MkdirAll(fsys.dir+"/"+path, perm)
type readWriteFSImpl struct {
}

func (fsys MkdirFsImpl) Open(name string) (fs.File, error) {
return os.OpenFile(fsys.dir+"/"+name, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0644)
func (fwfs readWriteFSImpl) Open(name string) (fs.File, error) {
return os.Open(name)
}

func (fsys MkdirFsImpl) OpenAtEnd(name string) (fs.File, error) {
file, err := os.OpenFile(fsys.dir+"/"+name, os.O_CREATE|os.O_RDWR, 0644)
func (fwfs readWriteFSImpl) OpenWritable(name string) (WritableFile, error) {
if err := os.MkdirAll(filepath.Dir(name), os.ModePerm); err != nil {
return nil, err
}
return os.OpenFile(name, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0644)
}

func (fwfs readWriteFSImpl) OpenAppendable(name string) (WritableFile, error) {
if err := os.MkdirAll(filepath.Dir(name), os.ModePerm); err != nil {
return nil, err
}
file, err := os.OpenFile(name, os.O_CREATE|os.O_RDWR, 0644)

if err != nil {
return nil, err
Expand All @@ -77,13 +82,16 @@ func (fsys MkdirFsImpl) OpenAtEnd(name string) (fs.File, error) {
if err != nil {
return nil, err
}

return file, nil
}

var gzipExtension = ".gz__"

func uploads(router *httprouter.Router, fsys MkdirFS) {
func safeResolve(baseDir string, relPath string) string {
return filepath.Join(baseDir, filepath.Clean(filepath.Join(string(os.PathSeparator), relPath)))
}

func uploads(router *httprouter.Router, baseDir string, fsys WriteFS) {
router.POST("/_apis/pipelines/workflows/:runId/artifacts", func(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
runID := params.ByName("runId")

Expand All @@ -108,19 +116,15 @@ func uploads(router *httprouter.Router, fsys MkdirFS) {
itemPath += gzipExtension
}

filePath := fmt.Sprintf("%s/%s", runID, itemPath)
safeRunPath := safeResolve(baseDir, runID)
safePath := safeResolve(safeRunPath, itemPath)

err := fsys.MkdirAll(path.Dir(filePath), os.ModePerm)
if err != nil {
panic(err)
}

file, err := func() (fs.File, error) {
file, err := func() (WritableFile, error) {
contentRange := req.Header.Get("Content-Range")
if contentRange != "" && !strings.HasPrefix(contentRange, "bytes 0-") {
return fsys.OpenAtEnd(filePath)
return fsys.OpenAppendable(safePath)
}
return fsys.Open(filePath)
return fsys.OpenWritable(safePath)
}()

if err != nil {
Expand Down Expand Up @@ -170,11 +174,13 @@ func uploads(router *httprouter.Router, fsys MkdirFS) {
})
}

func downloads(router *httprouter.Router, fsys fs.FS) {
func downloads(router *httprouter.Router, baseDir string, fsys fs.FS) {
router.GET("/_apis/pipelines/workflows/:runId/artifacts", func(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
runID := params.ByName("runId")

entries, err := fs.ReadDir(fsys, runID)
safePath := safeResolve(baseDir, runID)

entries, err := fs.ReadDir(fsys, safePath)
if err != nil {
panic(err)
}
Expand Down Expand Up @@ -204,12 +210,12 @@ func downloads(router *httprouter.Router, fsys fs.FS) {
router.GET("/download/:container", func(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
container := params.ByName("container")
itemPath := req.URL.Query().Get("itemPath")
dirPath := fmt.Sprintf("%s/%s", container, itemPath)
safePath := safeResolve(baseDir, filepath.Join(container, itemPath))

var files []ContainerItem
err := fs.WalkDir(fsys, dirPath, func(path string, entry fs.DirEntry, err error) error {
err := fs.WalkDir(fsys, safePath, func(path string, entry fs.DirEntry, err error) error {
if !entry.IsDir() {
rel, err := filepath.Rel(dirPath, path)
rel, err := filepath.Rel(safePath, path)
if err != nil {
panic(err)
}
Expand All @@ -218,7 +224,7 @@ func downloads(router *httprouter.Router, fsys fs.FS) {
rel = strings.TrimSuffix(rel, gzipExtension)

files = append(files, ContainerItem{
Path: fmt.Sprintf("%s/%s", itemPath, rel),
Path: filepath.Join(itemPath, rel),
ItemType: "file",
ContentLocation: fmt.Sprintf("http://%s/artifact/%s/%s/%s", req.Host, container, itemPath, rel),
})
Expand All @@ -245,10 +251,12 @@ func downloads(router *httprouter.Router, fsys fs.FS) {
router.GET("/artifact/*path", func(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
path := params.ByName("path")[1:]

file, err := fsys.Open(path)
safePath := safeResolve(baseDir, path)

file, err := fsys.Open(safePath)
if err != nil {
// try gzip file
file, err = fsys.Open(path + gzipExtension)
file, err = fsys.Open(safePath + gzipExtension)
if err != nil {
panic(err)
}
Expand All @@ -273,9 +281,9 @@ func Serve(ctx context.Context, artifactPath string, addr string, port string) c
router := httprouter.New()

logger.Debugf("Artifacts base path '%s'", artifactPath)
fs := os.DirFS(artifactPath)
uploads(router, MkdirFsImpl{artifactPath, fs})
downloads(router, fs)
fsys := readWriteFSImpl{}
uploads(router, artifactPath, fsys)
downloads(router, artifactPath, fsys)

server := &http.Server{
Addr: fmt.Sprintf("%s:%s", addr, port),
Expand Down
Loading

0 comments on commit 63ae215

Please sign in to comment.