mirror of https://gitlab.com/gitlab-org/cli.git
256 lines
5.8 KiB
Go
256 lines
5.8 KiB
Go
package ci
|
|
|
|
import (
|
|
"archive/zip"
|
|
"bytes"
|
|
"io"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"gitlab.com/gitlab-org/cli/pkg/iostreams"
|
|
|
|
"github.com/xanzy/go-gitlab"
|
|
"gitlab.com/gitlab-org/cli/api"
|
|
|
|
"github.com/google/shlex"
|
|
"gitlab.com/gitlab-org/cli/commands/cmdutils"
|
|
"gitlab.com/gitlab-org/cli/internal/config"
|
|
"gitlab.com/gitlab-org/cli/internal/glrepo"
|
|
"gitlab.com/gitlab-org/cli/pkg/git"
|
|
"gitlab.com/gitlab-org/cli/pkg/httpmock"
|
|
)
|
|
|
|
func doesFileExist(fileName string) bool {
|
|
_, err := os.Stat(fileName)
|
|
return err == nil
|
|
}
|
|
|
|
func createZipFile(t *testing.T, filename string) (string, string) {
|
|
tempPath, err := os.MkdirTemp("/tmp", "testing_directory")
|
|
require.NoError(t, err)
|
|
|
|
archive, err := os.CreateTemp(tempPath, "test.*.zip")
|
|
require.NoError(t, err)
|
|
defer archive.Close()
|
|
|
|
zipWriter := zip.NewWriter(archive)
|
|
|
|
f1, err := os.Open("./testdata/file.txt")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer f1.Close()
|
|
|
|
w1, err := zipWriter.Create(filename)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
if _, err := io.Copy(w1, f1); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
zipWriter.Close()
|
|
|
|
return tempPath, archive.Name()
|
|
}
|
|
|
|
func makeTestFactory() (factory *cmdutils.Factory, fakeHTTP *httpmock.Mocker) {
|
|
fakeHTTP = &httpmock.Mocker{
|
|
MatchURL: httpmock.PathAndQuerystring,
|
|
}
|
|
|
|
io, _, _, _ := iostreams.Test()
|
|
io.IsaTTY = false
|
|
io.IsInTTY = false
|
|
io.IsErrTTY = false
|
|
|
|
client := func(token, hostname string) (*api.Client, error) {
|
|
return api.TestClient(&http.Client{Transport: fakeHTTP}, token, hostname, false)
|
|
}
|
|
|
|
// FIXME as mentioned in ./commands/auth/status/status_test.go,
|
|
// httpmock seems to require a quick test run before it will work
|
|
_, err := client("", "gitlab.com")
|
|
if err != nil {
|
|
return nil, nil
|
|
}
|
|
|
|
factory = &cmdutils.Factory{
|
|
IO: io,
|
|
Config: func() (config.Config, error) {
|
|
return config.NewBlankConfig(), nil
|
|
},
|
|
HttpClient: func() (*gitlab.Client, error) {
|
|
a, err := client("xxxx", "gitlab.com")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return a.Lab(), err
|
|
},
|
|
BaseRepo: func() (glrepo.Interface, error) {
|
|
return glrepo.New("OWNER", "REPO"), nil
|
|
},
|
|
Remotes: func() (glrepo.Remotes, error) {
|
|
return glrepo.Remotes{
|
|
{
|
|
Remote: &git.Remote{Name: "origin"},
|
|
Repo: glrepo.New("OWNER", "REPO"),
|
|
},
|
|
}, nil
|
|
},
|
|
Branch: func() (string, error) {
|
|
return "feature", nil
|
|
},
|
|
}
|
|
|
|
return factory, fakeHTTP
|
|
}
|
|
|
|
func createSymlinkZip(t *testing.T) (string, string) {
|
|
tempPath, err := os.MkdirTemp("/tmp", "testing_directory")
|
|
require.NoError(t, err)
|
|
|
|
archive, err := os.CreateTemp(tempPath, "test.*.zip")
|
|
require.NoError(t, err)
|
|
defer archive.Close()
|
|
|
|
immutableFile, err := os.CreateTemp(tempPath, "immutable_file*.txt")
|
|
require.NoError(t, err)
|
|
|
|
immutableText := "Immutable text! GitLab is cool"
|
|
_, err = immutableFile.WriteString(immutableText)
|
|
require.NoError(t, err)
|
|
|
|
err = os.Symlink(immutableFile.Name(), tempPath+"/symlink_file.txt")
|
|
require.NoError(t, err)
|
|
|
|
zipWriter := zip.NewWriter(archive)
|
|
|
|
fixtureFile, err := os.Open("./testdata/file.txt")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer fixtureFile.Close()
|
|
|
|
zipFile, err := zipWriter.Create("symlink_file.txt")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
if _, err := io.Copy(zipFile, fixtureFile); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
zipWriter.Close()
|
|
|
|
return tempPath, archive.Name()
|
|
}
|
|
|
|
func Test_NewCmdRun(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
filename string
|
|
want string
|
|
customPath string
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "A regular filename",
|
|
filename: "cli-v1.22.0.json",
|
|
want: "cli-v1.22.0.json",
|
|
},
|
|
{
|
|
name: "A regular filename in a directory",
|
|
filename: "cli/cli-v1.22.0.json",
|
|
want: "cli/cli-v1.22.0.json",
|
|
},
|
|
{
|
|
name: "A filename with directory traversal",
|
|
filename: "cli-v1.../../22.0.zip",
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "A particularly nasty filename",
|
|
filename: "..././..././..././etc/password_file",
|
|
wantErr: true,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
factory, fakeHTTP := makeTestFactory()
|
|
tempPath, tempFileName := createZipFile(t, tt.filename)
|
|
// defer os.Remove(tempFileName)
|
|
|
|
fakeHTTP.RegisterResponder(http.MethodGet, `https://gitlab.com/api/v4/projects/OWNER%2FREPO/jobs/artifacts/main/download?job=secret_detection`,
|
|
httpmock.NewFileResponse(http.StatusOK, tempFileName))
|
|
|
|
cmd := NewCmdRun(factory)
|
|
|
|
argv, err := shlex.Split("main secret_detection")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
cmd.SetArgs(argv)
|
|
|
|
err = cmd.Flags().Set("path", tempPath)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
cmd.SetIn(&bytes.Buffer{})
|
|
cmd.SetOut(io.Discard)
|
|
cmd.SetErr(io.Discard)
|
|
|
|
_, err = cmd.ExecuteC()
|
|
filePathWanted := filepath.Join(tempPath, tt.want)
|
|
|
|
if tt.wantErr {
|
|
assert.Error(t, err, "Should error out if a path doesn't exist")
|
|
return
|
|
}
|
|
|
|
assert.NoError(t, err, "Should not have errors")
|
|
assert.True(t, doesFileExist(filePathWanted), "File should exist")
|
|
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
})
|
|
}
|
|
|
|
t.Run("symlink can't overwrite", func(t *testing.T) {
|
|
factory, fakeHTTP := makeTestFactory()
|
|
|
|
tempPath, tempFileName := createSymlinkZip(t)
|
|
defer os.Remove(tempFileName)
|
|
|
|
fakeHTTP.RegisterResponder(http.MethodGet, `https://gitlab.com/api/v4/projects/OWNER%2FREPO/jobs/artifacts/main/download?job=secret_detection`,
|
|
httpmock.NewFileResponse(http.StatusOK, tempFileName))
|
|
|
|
cmd := NewCmdRun(factory)
|
|
|
|
argv, err := shlex.Split("main secret_detection")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
cmd.SetArgs(argv)
|
|
|
|
err = cmd.Flags().Set("path", tempPath)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
cmd.SetIn(&bytes.Buffer{})
|
|
cmd.SetOut(io.Discard)
|
|
cmd.SetErr(io.Discard)
|
|
|
|
_, err = cmd.ExecuteC()
|
|
assert.Error(t, err, "file in artifact would overwrite a symbolic link- cannot extract")
|
|
})
|
|
}
|