-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
14 changed files
with
308 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
package submodule | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"net/url" | ||
"os" | ||
"strings" | ||
|
||
godeptypes "github.com/aquasecurity/go-dep-parser/pkg/types" | ||
"github.com/aquasecurity/trivy/pkg/fanal/analyzer" | ||
"github.com/aquasecurity/trivy/pkg/fanal/analyzer/language" | ||
"github.com/aquasecurity/trivy/pkg/fanal/types" | ||
|
||
"github.com/go-git/go-git/v5" | ||
giturls "github.com/whilp/git-urls" | ||
"golang.org/x/xerrors" | ||
) | ||
|
||
func init() { | ||
analyzer.RegisterAnalyzer(&gitSubmoduleAnalyzer{}) | ||
} | ||
|
||
const version = 1 | ||
|
||
type gitSubmoduleAnalyzer struct{} | ||
|
||
func (a gitSubmoduleAnalyzer) Analyze(_ context.Context, input analyzer.AnalysisInput) (*analyzer.AnalysisResult, error) { | ||
libs, deps, err := parseGitmodules(input.Dir) | ||
if err != nil { | ||
return nil, xerrors.Errorf("git repo parse error: %w", err) | ||
} | ||
|
||
return language.ToAnalysisResult(types.GitSubmodule, input.FilePath, "", libs, deps), nil | ||
} | ||
|
||
func (a gitSubmoduleAnalyzer) Required(_ string, fileInfo os.FileInfo) bool { | ||
return fileInfo.Name() == types.GitModules | ||
} | ||
|
||
func (a gitSubmoduleAnalyzer) Type() analyzer.Type { | ||
return analyzer.TypeGitSubmodule | ||
} | ||
|
||
func (a gitSubmoduleAnalyzer) Version() int { | ||
return version | ||
} | ||
|
||
func parseGitmodules(inputDir string) ([]godeptypes.Library, []godeptypes.Dependency, error) { | ||
repo, err := git.PlainOpen(inputDir) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
|
||
w, err := repo.Worktree() | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
|
||
submodules, err := w.Submodules() | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
|
||
libs, _ := parseSubmodules(repo, &submodules) | ||
return libs, nil, nil | ||
} | ||
|
||
func parseSubmodules(repo *git.Repository, submodules *git.Submodules) ([]godeptypes.Library, []godeptypes.Dependency) { | ||
var libs []godeptypes.Library | ||
var name *url.URL | ||
|
||
for _, submodule := range *submodules { | ||
remote := submodule.Config().URL | ||
|
||
if strings.HasPrefix(remote, "../") { | ||
// resolve relative URLs via root remote | ||
rootRemote, err := getRemoteUrl(repo) | ||
if err != nil { | ||
return nil, nil | ||
} | ||
|
||
baseUrl, _ := giturls.Parse(fmt.Sprintf("%s/", rootRemote)) | ||
name, _ = baseUrl.Parse(remote) | ||
} else { | ||
name, _ = giturls.Parse(remote) | ||
} | ||
|
||
status, _ := submodule.Status() | ||
version := status.Expected.String() | ||
|
||
libs = append(libs, godeptypes.Library{ | ||
Name: name.String(), | ||
Version: version, | ||
}) | ||
} | ||
|
||
return libs, nil | ||
} | ||
|
||
func getRemoteUrl(repo *git.Repository) (string, error) { | ||
remote, err := repo.Remote("origin") | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
return remote.Config().URLs[0], nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
package submodule | ||
|
||
import ( | ||
"context" | ||
"os" | ||
"os/exec" | ||
"path/filepath" | ||
"testing" | ||
|
||
"github.com/go-git/go-git/v5" | ||
"github.com/go-git/go-git/v5/config" | ||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
|
||
"github.com/aquasecurity/trivy/pkg/fanal/analyzer" | ||
"github.com/aquasecurity/trivy/pkg/fanal/types" | ||
"github.com/aquasecurity/trivy/pkg/utils" | ||
) | ||
|
||
func Test_gitSubmoduleAnalyzer_Analyze(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
filePath string | ||
want *analyzer.AnalysisResult | ||
}{ | ||
{ | ||
name: "https-url", | ||
filePath: "testdata/https-url.gitmodules", | ||
want: &analyzer.AnalysisResult{ | ||
Applications: []types.Application{ | ||
{ | ||
Type: types.GitSubmodule, | ||
FilePath: types.GitModules, | ||
Libraries: []types.Package{ | ||
{ | ||
Name: "https://github.com/org/repository.git", | ||
Version: "ca82a6dff817ec66f44342007202690a93763949", | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
{ | ||
name: "git-url", | ||
filePath: "testdata/git-url.gitmodules", | ||
want: &analyzer.AnalysisResult{ | ||
Applications: []types.Application{ | ||
{ | ||
Type: types.GitSubmodule, | ||
FilePath: types.GitModules, | ||
Libraries: []types.Package{ | ||
{ | ||
Name: "ssh://[email protected]/org/repository.git", | ||
Version: "ca82a6dff817ec66f44342007202690a93763949", | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
{ | ||
name: "ssh-url", | ||
filePath: "testdata/ssh-url.gitmodules", | ||
want: &analyzer.AnalysisResult{ | ||
Applications: []types.Application{ | ||
{ | ||
Type: types.GitSubmodule, | ||
FilePath: types.GitModules, | ||
Libraries: []types.Package{ | ||
{ | ||
Name: "ssh://[email protected]/org/repository.git", | ||
Version: "ca82a6dff817ec66f44342007202690a93763949", | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
{ | ||
name: "relative-url", | ||
filePath: "testdata/relative-url.gitmodules", | ||
want: &analyzer.AnalysisResult{ | ||
Applications: []types.Application{ | ||
{ | ||
Type: types.GitSubmodule, | ||
FilePath: types.GitModules, | ||
Libraries: []types.Package{ | ||
{ | ||
Name: "https://github.com/org/repository.git", | ||
Version: "ca82a6dff817ec66f44342007202690a93763949", | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
{ | ||
name: "missing-submodule", | ||
filePath: "testdata/missing-submodule.gitmodules", | ||
want: nil, | ||
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
currentDir, err := os.Getwd() | ||
require.NoError(t, err) | ||
|
||
dir := t.TempDir() | ||
destFilePath := filepath.Join(dir, types.GitModules) | ||
|
||
_, err = utils.CopyFile(tt.filePath, destFilePath) | ||
require.NoError(t, err) | ||
|
||
err = initRepoWithSubmodules(dir) | ||
require.NoError(t, err) | ||
|
||
err = os.Chdir(dir) | ||
require.NoError(t, err) | ||
defer os.Chdir(currentDir) | ||
|
||
a := gitSubmoduleAnalyzer{} | ||
got, err := a.Analyze(context.Background(), analyzer.AnalysisInput{ | ||
Dir: dir, | ||
FilePath: types.GitModules, | ||
}) | ||
assert.Equal(t, tt.want, got) | ||
}) | ||
} | ||
} | ||
|
||
func initRepoWithSubmodules(dir string) error { | ||
repo, err := git.PlainInit(dir, false) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
_, err = repo.CreateRemote(&config.RemoteConfig{ | ||
Name: "origin", | ||
URLs: []string{"https://github.com/org/repository.git"}, | ||
}) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
updateIndexCmd := exec.Command( | ||
"git", | ||
"update-index", | ||
"--add", | ||
"--cacheinfo", | ||
"160000", | ||
"ca82a6dff817ec66f44342007202690a93763949", | ||
"submodule", | ||
) | ||
updateIndexCmd.Dir = dir | ||
updateIndexCmd.Run() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# Git submodule testdata | ||
|
||
The examples in this testdata directory test a few common Git URL formats. For a full | ||
list of supported Git URL formats, see: | ||
https://stackoverflow.com/questions/31801271/what-are-the-supported-git-url-formats | ||
|
||
For the git plumbing commands involved in the faked remote submodule test setup, see | ||
https://stackoverflow.com/questions/34562333/is-there-a-way-to-git-submodule-add-a-repo-without-cloning-it. | ||
|
||
Files here are not valid Git submodule configuration filenames. They are copied in each test case | ||
to `t.TempDir` as `.gitmodules`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
[submodule "submodule"] | ||
path = submodule | ||
url = [email protected]:org/repository.git |
3 changes: 3 additions & 0 deletions
3
pkg/fanal/analyzer/git/submodule/testdata/https-url.gitmodules
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
[submodule "submodule"] | ||
path = submodule | ||
url = https://github.com/org/repository.git |
1 change: 1 addition & 0 deletions
1
pkg/fanal/analyzer/git/submodule/testdata/missing-submodule.gitmodules
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
# This repository includes a valid entry in .git/index but no .gitmodules entry |
3 changes: 3 additions & 0 deletions
3
pkg/fanal/analyzer/git/submodule/testdata/relative-url.gitmodules
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
[submodule "submodule"] | ||
path = submodule | ||
url = ../repository.git |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
[submodule "submodule"] | ||
path = submodule | ||
url = ssh://[email protected]/org/repository.git |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters