Skip to content

Commit

Permalink
Expose git.CloneOptions when fetching remote artifacts
Browse files Browse the repository at this point in the history
  • Loading branch information
cjnosal committed Apr 8, 2021
1 parent 048c06d commit ca69616
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 40 deletions.
63 changes: 39 additions & 24 deletions artifact/remote/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,39 +5,49 @@ import (
"net/url"
"os"

"github.com/aquasecurity/fanal/analyzer"

git "github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/transport"

"github.com/aquasecurity/fanal/analyzer"
"github.com/aquasecurity/fanal/artifact"
"github.com/aquasecurity/fanal/artifact/local"
"github.com/aquasecurity/fanal/cache"
"github.com/aquasecurity/fanal/remote"
)

func NewArtifact(rawurl string, c cache.ArtifactCache, disabled []analyzer.Type) (artifact.Artifact, func(), error) {
func NewArtifact(remoteOpts remote.Remote, c cache.ArtifactCache, disabled []analyzer.Type) (artifact.Artifact, func(), error) {
cleanup := func() {}

u, err := newURL(rawurl)
u, err := newURL(remoteOpts.CloneOpts.URL)
if err != nil {
return nil, cleanup, err
}
remoteOpts.CloneOpts.URL = u

tmpDir, err := ioutil.TempDir("", "fanal-remote")
tmpDir, err := ioutil.TempDir(remoteOpts.ParentDirectory, "fanal-remote")
if err != nil {
return nil, cleanup, err
}
cleanup = func() {
_ = os.RemoveAll(tmpDir)
}

_, err = git.PlainClone(tmpDir, false, &git.CloneOptions{
URL: u.String(),
Progress: os.Stdout,
Depth: 1,
})
repo, err := git.PlainClone(tmpDir, remoteOpts.IsBare, remoteOpts.CloneOpts)
if err != nil {
return nil, cleanup, err
}

cleanup = func() {
_ = os.RemoveAll(tmpDir)
if remoteOpts.Commit != "" {
tree, err := repo.Worktree()
if err != nil {
return nil, cleanup, err
}
err = tree.Checkout(&git.CheckoutOptions{
Hash: plumbing.NewHash(remoteOpts.Commit),
})
if err != nil {
return nil, cleanup, err
}
}

// JAR/WAR/EAR doesn't need to be analyzed in git repositories.
Expand All @@ -46,16 +56,21 @@ func NewArtifact(rawurl string, c cache.ArtifactCache, disabled []analyzer.Type)
return local.NewArtifact(tmpDir, c, disabled), cleanup, nil
}

func newURL(rawurl string) (*url.URL, error) {
u, err := url.Parse(rawurl)
if err != nil {
return nil, err
}
// "https://" can be omitted
// e.g. github.com/aquasecurity/fanal
if u.Scheme == "" {
u.Scheme = "https"
func newURL(rawurl string) (string, error) {
u, err := url.Parse(rawurl) // fails on ssh urls
if err == nil {
// "https://" can be omitted
// e.g. github.com/aquasecurity/fanal
if u.Scheme == "" {
u.Scheme = "https"
}
rawurl = u.String()
} else {
u, err := transport.NewEndpoint(rawurl) // defaults to file://
if err != nil {
return "", err
}
rawurl = u.String() // ssh or file url
}

return u, nil
return rawurl, nil
}
89 changes: 75 additions & 14 deletions artifact/remote/git_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ import (
"net/http/httptest"
"testing"

git "github.com/go-git/go-git/v5"
"github.com/sosedoff/gitkit"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/aquasecurity/fanal/cache"
remotecfg "github.com/aquasecurity/fanal/remote"
)

func setupGitServer() (*httptest.Server, error) {
Expand All @@ -34,43 +36,95 @@ func TestNewArtifact(t *testing.T) {
defer ts.Close()

type args struct {
rawurl string
remote remotecfg.Remote
c cache.ArtifactCache
}
tests := []struct {
name string
args args
wantErr bool
wantErr string
}{
{
name: "happy path",
args: args{
rawurl: ts.URL + "/test.git",
c: nil,
remote: remotecfg.Remote{
IsBare: false,
CloneOpts: &git.CloneOptions{
URL: ts.URL + "/test.git",
Depth: 1,
},
},
c: nil,
},
},
{
name: "happy path commit",
args: args{
remote: remotecfg.Remote{
IsBare: false,
Commit: "HEAD~1",
CloneOpts: &git.CloneOptions{
URL: ts.URL + "/test.git",
Depth: 1,
},
},
c: nil,
},
},
{
name: "sad path",
name: "sad path unknown repo",
args: args{
rawurl: ts.URL + "/unknown.git",
c: nil,
remote: remotecfg.Remote{
IsBare: false,
CloneOpts: &git.CloneOptions{
URL: ts.URL + "/unknown.git",
Depth: 1,
},
},
c: nil,
},
wantErr: true,
wantErr: "repository not found",
},
{
name: "sad path unknown commit",
args: args{
remote: remotecfg.Remote{
IsBare: false,
Commit: "baddigest",
CloneOpts: &git.CloneOptions{
URL: ts.URL + "/test.git",
Depth: 1,
},
},
c: nil,
},
wantErr: "object not found",
},
{
name: "invalid url",
args: args{
rawurl: "ht tp://foo.com",
c: nil,
remote: remotecfg.Remote{
IsBare: false,
CloneOpts: &git.CloneOptions{
URL: "ht tp://foo.com",
Depth: 1,
},
},
c: nil,
},
wantErr: true,
wantErr: "first path segment in URL cannot contain colon",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
_, cleanup, err := NewArtifact(tt.args.rawurl, tt.args.c, nil)
assert.Equal(t, tt.wantErr, err != nil)
_, cleanup, err := NewArtifact(tt.args.remote, tt.args.c, nil)
if tt.wantErr != "" {
require.NotNil(t, err)
assert.Contains(t, err.Error(), tt.wantErr)
} else {
require.NoError(t, err)
}
defer cleanup()
})
}
Expand Down Expand Up @@ -100,6 +154,13 @@ func Test_newURL(t *testing.T) {
},
want: "https://github.com/aquasecurity/fanal",
},
{
name: "happy path: ssh url",
args: args{
rawurl: "github.com:foo/bar",
},
want: "github.com:foo/bar",
},
{
name: "sad path: invalid url",
args: args{
Expand All @@ -119,7 +180,7 @@ func Test_newURL(t *testing.T) {
require.NoError(t, err)
}

assert.Equal(t, tt.want, got.String())
assert.Equal(t, tt.want, got)
})
}
}
15 changes: 13 additions & 2 deletions cmd/fanal/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"strings"
"time"

git "github.com/go-git/go-git/v5"
"github.com/go-redis/redis/v8"
"github.com/urfave/cli/v2"
"golang.org/x/xerrors"
Expand Down Expand Up @@ -41,6 +42,7 @@ import (
"github.com/aquasecurity/fanal/artifact/remote"
"github.com/aquasecurity/fanal/cache"
"github.com/aquasecurity/fanal/image"
remotecfg "github.com/aquasecurity/fanal/remote"
"github.com/aquasecurity/fanal/types"
"github.com/aquasecurity/fanal/utils"
)
Expand Down Expand Up @@ -212,6 +214,15 @@ func localArtifact(dir string, c cache.ArtifactCache) artifact.Artifact {
return local.NewArtifact(dir, c, nil)
}

func remoteArtifact(dir string, c cache.ArtifactCache) (artifact.Artifact, func(), error) {
return remote.NewArtifact(dir, c, nil)
func remoteArtifact(url string, c cache.ArtifactCache) (artifact.Artifact, func(), error) {
opts := &git.CloneOptions{
URL: url,
Depth: 1,
Progress: os.Stdout,
}
config := remotecfg.Remote{
IsBare: false,
CloneOpts: opts,
}
return remote.NewArtifact(config, c, nil)
}
25 changes: 25 additions & 0 deletions remote/git.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package remote

import (
git "github.com/go-git/go-git/v5"
)

type Remote struct {
ParentDirectory string
IsBare bool
Commit string
CloneOpts *git.CloneOptions
}

func NewGitRemote(parentDirectory string, isBare bool, commit string, cloneOpts *git.CloneOptions) (Remote, error) {
err := cloneOpts.Validate()
if err != nil {
return Remote{}, err
}
return Remote{
ParentDirectory: parentDirectory,
IsBare: isBare,
Commit: commit,
CloneOpts: cloneOpts,
}, nil
}

0 comments on commit ca69616

Please sign in to comment.