Support azure git links (#1662)

* Support azure git links.

* update comment.

* update test names.
This commit is contained in:
ahrav 2023-08-24 14:36:52 -07:00 committed by GitHub
parent f2bfcc7ac6
commit 4f4a79f62b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 133 additions and 74 deletions

View file

@ -2,6 +2,7 @@ package giturl
import (
"net/url"
"strconv"
"strings"
"github.com/pkg/errors"
@ -13,8 +14,29 @@ const (
providerGithub provider = "Github"
providerGitlab provider = "Gitlab"
providerBitbucket provider = "Bitbucket"
providerAzure provider = "Azure"
urlGithub = "github.com/"
urlGitlab = "gitlab.com/"
urlBitbucket = "bitbucket.org/"
urlAzure = "dev.azure.com/"
)
func determineProvider(repo string) provider {
switch {
case strings.Contains(repo, urlGithub):
return providerGithub
case strings.Contains(repo, urlGitlab):
return providerGitlab
case strings.Contains(repo, urlBitbucket):
return providerBitbucket
case strings.Contains(repo, urlAzure):
return providerAzure
default:
return ""
}
}
func NormalizeBitbucketRepo(repoURL string) (string, error) {
if !strings.HasPrefix(repoURL, "https") {
return "", errors.New("Bitbucket requires https repo urls: e.g. https://bitbucket.org/org/repo.git")
@ -88,3 +110,35 @@ func NormalizeOrgRepoURL(provider provider, repoURL string) (string, error) {
parsed.Path += ".git"
return parsed.String(), nil
}
// GenerateLink crafts a link to the specific file from a commit.
// Supports GitHub, GitLab, Bitbucket, and Azure Repos.
// If the provider supports hyperlinks to specific lines, the line number will be included.
func GenerateLink(repo, commit, file string, line int64) string {
switch determineProvider(repo) {
case providerBitbucket:
return repo[:len(repo)-4] + "/commits/" + commit
case providerGithub, providerGitlab:
var baseLink string
if file == "" {
baseLink = repo[:len(repo)-4] + "/commit/" + commit
} else {
baseLink = repo[:len(repo)-4] + "/blob/" + commit + "/" + file
if line > 0 {
baseLink += "#L" + strconv.FormatInt(line, 10)
}
}
return baseLink
case providerAzure:
baseLink := repo + "?path=" + file + "&version=GB" + commit
if line > 0 {
baseLink += "&line=" + strconv.FormatInt(line, 10)
}
return baseLink
default:
return ""
}
}

View file

@ -7,6 +7,8 @@ import (
)
func Test_NormalizeOrgRepoURL(t *testing.T) {
t.Parallel()
tests := map[string]struct {
Provider provider
Repo string
@ -43,6 +45,8 @@ func Test_NormalizeOrgRepoURL(t *testing.T) {
}
func Test_NormalizeBitbucketRepo(t *testing.T) {
t.Parallel()
tests := map[string]struct {
Repo string
Out string
@ -69,6 +73,8 @@ func Test_NormalizeBitbucketRepo(t *testing.T) {
}
func Test_NormalizeGitlabRepo(t *testing.T) {
t.Parallel()
tests := map[string]struct {
Repo string
Out string
@ -93,3 +99,73 @@ func Test_NormalizeGitlabRepo(t *testing.T) {
}
}
}
func TestGenerateLink(t *testing.T) {
t.Parallel()
type args struct {
repo string
commit string
file string
line int64
}
tests := []struct {
name string
args args
want string
}{
{
name: "github link gen",
args: args{
repo: "https://github.com/trufflesec-julian/confluence-go-api.git",
commit: "047b4a2ba42fc5b6c0bd535c5307434a666db5ec",
file: ".gitignore",
},
want: "https://github.com/trufflesec-julian/confluence-go-api/blob/047b4a2ba42fc5b6c0bd535c5307434a666db5ec/.gitignore",
},
{
name: "github link gen with line",
args: args{
repo: "https://github.com/trufflesec-julian/confluence-go-api.git",
commit: "047b4a2ba42fc5b6c0bd535c5307434a666db5ec",
file: ".gitignore",
line: int64(4),
},
want: "https://github.com/trufflesec-julian/confluence-go-api/blob/047b4a2ba42fc5b6c0bd535c5307434a666db5ec/.gitignore#L4",
},
{
name: "github link gen - no file",
args: args{
repo: "https://github.com/trufflesec-julian/confluence-go-api.git",
commit: "047b4a2ba42fc5b6c0bd535c5307434a666db5ec",
},
want: "https://github.com/trufflesec-julian/confluence-go-api/commit/047b4a2ba42fc5b6c0bd535c5307434a666db5ec",
},
{
name: "Azure link gen",
args: args{
repo: "https://dev.azure.com/org/project/_git/repo",
commit: "abcdef",
file: "main.go",
},
want: "https://dev.azure.com/org/project/_git/repo?path=main.go&version=GBabcdef",
},
{
name: "Azure link gen with line",
args: args{
repo: "https://dev.azure.com/org/project/_git/repo",
commit: "abcdef",
file: "main.go",
line: int64(20),
},
want: "https://dev.azure.com/org/project/_git/repo?path=main.go&version=GBabcdef&line=20",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := GenerateLink(tt.args.repo, tt.args.commit, tt.args.file, tt.args.line); got != tt.want {
t.Errorf("generateLink() = %v, want %v", got, tt.want)
}
})
}
}

View file

@ -9,7 +9,6 @@ import (
"os/exec"
"path/filepath"
"runtime"
"strconv"
"strings"
"sync/atomic"
"time"
@ -693,28 +692,6 @@ func normalizeConfig(scanOptions *ScanOptions, repo *git.Repository) (err error)
return nil
}
// GenerateLink crafts a link to the specific file from a commit. This works in most major git providers (Github/Gitlab)
func GenerateLink(repo, commit, file string, line int64) string {
// bitbucket links are commits not commit...
if strings.Contains(repo, "bitbucket.org/") {
return repo[:len(repo)-4] + "/commits/" + commit
}
var link string
if file == "" {
link = repo[:len(repo)-4] + "/commit/" + commit
} else {
link = repo[:len(repo)-4] + "/blob/" + commit + "/" + file
// Both GitHub and Gitlab support hyperlinking to a specific line with #L<number>, e.g.:
// https://github.com/trufflesecurity/trufflehog/blob/e856a6890d0da5a218f4f9283500b80043884641/go.mod#L169
// https://gitlab.com/pdftk-java/pdftk/-/blob/88559a08f34175b6fae76c40a88f0377f64a12d7/java/com/gitlab/pdftk_java/report.java#L893
if line > 0 && (strings.Contains(repo, "github") || strings.Contains(repo, "gitlab")) {
link += "#L" + strconv.FormatInt(line, 10)
}
}
return link
}
func stripPassword(u string) (string, error) {
if strings.HasPrefix(u, "git@") {
return u, nil

View file

@ -151,55 +151,6 @@ func TestSource_Scan(t *testing.T) {
}
}
func Test_generateLink(t *testing.T) {
type args struct {
repo string
commit string
file string
line int64
}
tests := []struct {
name string
args args
want string
}{
{
name: "test link gen",
args: args{
repo: "https://github.com/trufflesec-julian/confluence-go-api.git",
commit: "047b4a2ba42fc5b6c0bd535c5307434a666db5ec",
file: ".gitignore",
},
want: "https://github.com/trufflesec-julian/confluence-go-api/blob/047b4a2ba42fc5b6c0bd535c5307434a666db5ec/.gitignore",
},
{
name: "test link gen",
args: args{
repo: "https://github.com/trufflesec-julian/confluence-go-api.git",
commit: "047b4a2ba42fc5b6c0bd535c5307434a666db5ec",
file: ".gitignore",
line: int64(4),
},
want: "https://github.com/trufflesec-julian/confluence-go-api/blob/047b4a2ba42fc5b6c0bd535c5307434a666db5ec/.gitignore#L4",
},
{
name: "test link gen - no file",
args: args{
repo: "https://github.com/trufflesec-julian/confluence-go-api.git",
commit: "047b4a2ba42fc5b6c0bd535c5307434a666db5ec",
},
want: "https://github.com/trufflesec-julian/confluence-go-api/commit/047b4a2ba42fc5b6c0bd535c5307434a666db5ec",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := GenerateLink(tt.args.repo, tt.args.commit, tt.args.file, tt.args.line); got != tt.want {
t.Errorf("generateLink() = %v, want %v", got, tt.want)
}
})
}
}
// We ran into an issue where upgrading a dependency caused the git patch chunking to break
// So this test exists to make sure that when something changes, we know about it.
func TestSource_Chunks_Integration(t *testing.T) {

View file

@ -29,6 +29,7 @@ import (
"github.com/trufflesecurity/trufflehog/v3/pkg/cache/memory"
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
"github.com/trufflesecurity/trufflehog/v3/pkg/context"
"github.com/trufflesecurity/trufflehog/v3/pkg/giturl"
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/credentialspb"
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/source_metadatapb"
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/sourcespb"
@ -261,7 +262,7 @@ func (s *Source) Init(aCtx context.Context, name string, jobID, sourceID int64,
File: sanitizer.UTF8(file),
Email: sanitizer.UTF8(email),
Repository: sanitizer.UTF8(repository),
Link: git.GenerateLink(repository, commit, file, line),
Link: giturl.GenerateLink(repository, commit, file, line),
Timestamp: sanitizer.UTF8(timestamp),
Line: line,
Visibility: s.visibilityOf(aCtx, repository),

View file

@ -127,7 +127,7 @@ func (s *Source) Init(_ context.Context, name string, jobId, sourceId int64, ver
File: sanitizer.UTF8(file),
Email: sanitizer.UTF8(email),
Repository: sanitizer.UTF8(repository),
Link: git.GenerateLink(repository, commit, file, line),
Link: giturl.GenerateLink(repository, commit, file, line),
Timestamp: sanitizer.UTF8(timestamp),
Line: line,
},