github.com/devseccon/trivy@v0.47.1-0.20231123133102-bd902a0bd996/pkg/fanal/artifact/repo/git_test.go (about)

     1  //go:build unix
     2  
     3  package repo
     4  
     5  import (
     6  	"context"
     7  	"net/http/httptest"
     8  	"testing"
     9  
    10  	"github.com/sosedoff/gitkit"
    11  	"github.com/stretchr/testify/assert"
    12  	"github.com/stretchr/testify/require"
    13  
    14  	"github.com/devseccon/trivy/pkg/fanal/artifact"
    15  	"github.com/devseccon/trivy/pkg/fanal/cache"
    16  	"github.com/devseccon/trivy/pkg/fanal/types"
    17  
    18  	_ "github.com/devseccon/trivy/pkg/fanal/analyzer/config/all"
    19  	_ "github.com/devseccon/trivy/pkg/fanal/analyzer/secret"
    20  )
    21  
    22  func setupGitServer() (*httptest.Server, error) {
    23  	service := gitkit.New(gitkit.Config{
    24  		Dir:        "./testdata",
    25  		AutoCreate: false,
    26  	})
    27  
    28  	if err := service.Setup(); err != nil {
    29  		return nil, err
    30  	}
    31  
    32  	ts := httptest.NewServer(service)
    33  
    34  	return ts, nil
    35  }
    36  
    37  func TestNewArtifact(t *testing.T) {
    38  	ts, err := setupGitServer()
    39  	require.NoError(t, err)
    40  	defer ts.Close()
    41  
    42  	type args struct {
    43  		target     string
    44  		c          cache.ArtifactCache
    45  		noProgress bool
    46  		repoBranch string
    47  		repoTag    string
    48  		repoCommit string
    49  	}
    50  	tests := []struct {
    51  		name      string
    52  		args      args
    53  		assertion assert.ErrorAssertionFunc
    54  	}{
    55  		{
    56  			name: "remote repo",
    57  			args: args{
    58  				target:     ts.URL + "/test.git",
    59  				c:          nil,
    60  				noProgress: false,
    61  			},
    62  			assertion: assert.NoError,
    63  		},
    64  		{
    65  			name: "local repo",
    66  			args: args{
    67  				target:     "testdata",
    68  				c:          nil,
    69  				noProgress: false,
    70  			},
    71  			assertion: assert.NoError,
    72  		},
    73  		{
    74  			name: "happy noProgress",
    75  			args: args{
    76  				target:     ts.URL + "/test.git",
    77  				c:          nil,
    78  				noProgress: true,
    79  			},
    80  			assertion: assert.NoError,
    81  		},
    82  		{
    83  			name: "branch",
    84  			args: args{
    85  				target:     ts.URL + "/test.git",
    86  				c:          nil,
    87  				repoBranch: "valid-branch",
    88  			},
    89  			assertion: assert.NoError,
    90  		},
    91  		{
    92  			name: "tag",
    93  			args: args{
    94  				target:  ts.URL + "/test.git",
    95  				c:       nil,
    96  				repoTag: "v1.0.0",
    97  			},
    98  			assertion: assert.NoError,
    99  		},
   100  		{
   101  			name: "commit",
   102  			args: args{
   103  				target:     ts.URL + "/test.git",
   104  				c:          nil,
   105  				repoCommit: "6ac152fe2b87cb5e243414df71790a32912e778d",
   106  			},
   107  			assertion: assert.NoError,
   108  		},
   109  		{
   110  			name: "sad path",
   111  			args: args{
   112  				target:     ts.URL + "/unknown.git",
   113  				c:          nil,
   114  				noProgress: false,
   115  			},
   116  			assertion: func(t assert.TestingT, err error, args ...interface{}) bool {
   117  				return assert.ErrorContains(t, err, "repository not found")
   118  			},
   119  		},
   120  		{
   121  			name: "invalid url",
   122  			args: args{
   123  				target:     "ht tp://foo.com",
   124  				c:          nil,
   125  				noProgress: false,
   126  			},
   127  			assertion: func(t assert.TestingT, err error, args ...interface{}) bool {
   128  				return assert.ErrorContains(t, err, "url parse error")
   129  			},
   130  		},
   131  		{
   132  			name: "invalid branch",
   133  			args: args{
   134  				target:     ts.URL + "/test.git",
   135  				c:          nil,
   136  				repoBranch: "invalid-branch",
   137  			},
   138  			assertion: func(t assert.TestingT, err error, args ...interface{}) bool {
   139  				return assert.ErrorContains(t, err, `couldn't find remote ref "refs/heads/invalid-branch"`)
   140  			},
   141  		},
   142  		{
   143  			name: "invalid tag",
   144  			args: args{
   145  				target:  ts.URL + "/test.git",
   146  				c:       nil,
   147  				repoTag: "v1.0.9",
   148  			},
   149  			assertion: func(t assert.TestingT, err error, args ...interface{}) bool {
   150  				return assert.ErrorContains(t, err, `couldn't find remote ref "refs/tags/v1.0.9"`)
   151  			},
   152  		},
   153  		{
   154  			name: "invalid commit",
   155  			args: args{
   156  				target:     ts.URL + "/test.git",
   157  				c:          nil,
   158  				repoCommit: "6ac152fe2b87cb5e243414df71790a32912e778e",
   159  			},
   160  			assertion: func(t assert.TestingT, err error, args ...interface{}) bool {
   161  				return assert.ErrorContains(t, err, "git checkout error: object not found")
   162  			},
   163  		},
   164  	}
   165  
   166  	for _, tt := range tests {
   167  		t.Run(tt.name, func(t *testing.T) {
   168  			_, cleanup, err := NewArtifact(tt.args.target, tt.args.c, artifact.Option{
   169  				NoProgress: tt.args.noProgress,
   170  				RepoBranch: tt.args.repoBranch,
   171  				RepoTag:    tt.args.repoTag,
   172  				RepoCommit: tt.args.repoCommit,
   173  			})
   174  			tt.assertion(t, err)
   175  			defer cleanup()
   176  		})
   177  	}
   178  }
   179  
   180  func TestArtifact_Inspect(t *testing.T) {
   181  	ts, err := setupGitServer()
   182  	require.NoError(t, err)
   183  	defer ts.Close()
   184  
   185  	tests := []struct {
   186  		name    string
   187  		rawurl  string
   188  		want    types.ArtifactReference
   189  		wantErr bool
   190  	}{
   191  		{
   192  			name:   "happy path",
   193  			rawurl: ts.URL + "/test.git",
   194  			want: types.ArtifactReference{
   195  				Name: ts.URL + "/test.git",
   196  				Type: types.ArtifactRepository,
   197  				ID:   "sha256:1fa928c33b16a335015ce96e1384127f8463c4f27ed0786806a6d4584b63d091",
   198  				BlobIDs: []string{
   199  					"sha256:1fa928c33b16a335015ce96e1384127f8463c4f27ed0786806a6d4584b63d091",
   200  				},
   201  			},
   202  		},
   203  	}
   204  
   205  	for _, tt := range tests {
   206  		t.Run(tt.name, func(t *testing.T) {
   207  			fsCache, err := cache.NewFSCache(t.TempDir())
   208  			require.NoError(t, err)
   209  
   210  			art, cleanup, err := NewArtifact(tt.rawurl, fsCache, artifact.Option{})
   211  			require.NoError(t, err)
   212  			defer cleanup()
   213  
   214  			ref, err := art.Inspect(context.Background())
   215  			assert.NoError(t, err)
   216  			assert.Equal(t, tt.want, ref)
   217  		})
   218  	}
   219  }
   220  
   221  func Test_newURL(t *testing.T) {
   222  	type args struct {
   223  		rawurl string
   224  	}
   225  	tests := []struct {
   226  		name    string
   227  		args    args
   228  		want    string
   229  		wantErr string
   230  	}{
   231  		{
   232  			name: "happy path",
   233  			args: args{
   234  				rawurl: "https://github.com/aquasecurity/fanal",
   235  			},
   236  			want: "https://github.com/aquasecurity/fanal",
   237  		},
   238  		{
   239  			name: "happy path: no scheme",
   240  			args: args{
   241  				rawurl: "github.com/aquasecurity/fanal",
   242  			},
   243  			want: "https://github.com/aquasecurity/fanal",
   244  		},
   245  		{
   246  			name: "sad path: invalid url",
   247  			args: args{
   248  				rawurl: "ht tp://foo.com",
   249  			},
   250  			wantErr: "first path segment in URL cannot contain colon",
   251  		},
   252  	}
   253  	for _, tt := range tests {
   254  		t.Run(tt.name, func(t *testing.T) {
   255  			got, err := newURL(tt.args.rawurl)
   256  			if tt.wantErr != "" {
   257  				require.NotNil(t, err)
   258  				assert.Contains(t, err.Error(), tt.wantErr)
   259  				return
   260  			} else {
   261  				require.NoError(t, err)
   262  			}
   263  
   264  			assert.Equal(t, tt.want, got.String())
   265  		})
   266  	}
   267  }