diff --git a/internal/zip/fixtures/myproject.zip b/internal/zip/fixtures/myproject.zip new file mode 100644 index 000000000..2fdf3f90c Binary files /dev/null and b/internal/zip/fixtures/myproject.zip differ diff --git a/pkg/cmd/run/download/zip.go b/internal/zip/zip.go similarity index 80% rename from pkg/cmd/run/download/zip.go rename to internal/zip/zip.go index bb504dde1..8cef5c30b 100644 --- a/pkg/cmd/run/download/zip.go +++ b/internal/zip/zip.go @@ -1,4 +1,4 @@ -package download +package zip import ( "archive/zip" @@ -17,7 +17,11 @@ const ( execMode os.FileMode = 0755 ) -func extractZip(zr *zip.Reader, destDir safepaths.Absolute) error { +// ExtractZip extracts the contents of a zip archive to destDir. +// Files that would result in path traversal are silently skipped. +// Files that would produce any other error cause the extraction to be aborted, +// and the error is returned. +func ExtractZip(zr *zip.Reader, destDir safepaths.Absolute) error { for _, zf := range zr.File { fpath, err := destDir.Join(zf.Name) if err != nil { diff --git a/pkg/cmd/run/download/zip_test.go b/internal/zip/zip_test.go similarity index 89% rename from pkg/cmd/run/download/zip_test.go rename to internal/zip/zip_test.go index 2584371b4..37e83661c 100644 --- a/pkg/cmd/run/download/zip_test.go +++ b/internal/zip/zip_test.go @@ -1,4 +1,4 @@ -package download +package zip import ( "archive/zip" @@ -19,7 +19,7 @@ func Test_extractZip(t *testing.T) { require.NoError(t, err) defer zipFile.Close() - err = extractZip(&zipFile.Reader, extractPath) + err = ExtractZip(&zipFile.Reader, extractPath) require.NoError(t, err) _, err = os.Stat(filepath.Join(extractPath.String(), "src", "main.go")) diff --git a/pkg/cmd/run/download/http.go b/pkg/cmd/run/download/http.go index 783c8495e..09293b056 100644 --- a/pkg/cmd/run/download/http.go +++ b/pkg/cmd/run/download/http.go @@ -10,6 +10,7 @@ import ( "github.com/cli/cli/v2/api" "github.com/cli/cli/v2/internal/ghrepo" "github.com/cli/cli/v2/internal/safepaths" + ghzip "github.com/cli/cli/v2/internal/zip" "github.com/cli/cli/v2/pkg/cmd/run/shared" ) @@ -62,7 +63,7 @@ func downloadArtifact(httpClient *http.Client, url string, destDir safepaths.Abs if err != nil { return fmt.Errorf("error extracting zip archive: %w", err) } - if err := extractZip(zipfile, destDir); err != nil { + if err := ghzip.ExtractZip(zipfile, destDir); err != nil { return fmt.Errorf("error extracting zip archive: %w", err) }