Instrument GitHub source with a UnitReporter (#3284)
* Fix GitHub integration test * Instrument GitHub source with a UnitReporter The reporter is currently unused, but is the first step to support scanning while enumerating. * Update GitHub unit tests
This commit is contained in:
@@ -75,6 +75,32 @@ type Source struct {
|
|||||||
sources.CommonSourceUnitUnmarshaller
|
sources.CommonSourceUnitUnmarshaller
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------------
|
||||||
|
// RepoUnit and GistUnit are implementations of SourceUnit used during
|
||||||
|
// enumeration. The different types aren't strictly necessary, but are a bit
|
||||||
|
// more explicit and allow type checking/safety.
|
||||||
|
|
||||||
|
var _ sources.SourceUnit = (*RepoUnit)(nil)
|
||||||
|
var _ sources.SourceUnit = (*GistUnit)(nil)
|
||||||
|
|
||||||
|
type RepoUnit struct {
|
||||||
|
name string
|
||||||
|
url string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r RepoUnit) SourceUnitID() (string, sources.SourceUnitKind) { return r.url, "repo" }
|
||||||
|
func (r RepoUnit) Display() string { return r.name }
|
||||||
|
|
||||||
|
type GistUnit struct {
|
||||||
|
name string
|
||||||
|
url string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g GistUnit) SourceUnitID() (string, sources.SourceUnitKind) { return g.url, "gist" }
|
||||||
|
func (g GistUnit) Display() string { return g.name }
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------------
|
||||||
|
|
||||||
// WithCustomContentWriter sets the useCustomContentWriter flag on the source.
|
// WithCustomContentWriter sets the useCustomContentWriter flag on the source.
|
||||||
func (s *Source) WithCustomContentWriter() { s.useCustomContentWriter = true }
|
func (s *Source) WithCustomContentWriter() { s.useCustomContentWriter = true }
|
||||||
|
|
||||||
@@ -313,25 +339,30 @@ func (s *Source) Chunks(ctx context.Context, chunksChan chan *sources.Chunk, tar
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Source) enumerate(ctx context.Context) error {
|
func (s *Source) enumerate(ctx context.Context) error {
|
||||||
|
// Create a reporter that does nothing for now.
|
||||||
|
noopReporter := sources.VisitorReporter{
|
||||||
|
VisitUnit: func(ctx context.Context, su sources.SourceUnit) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
// I'm not wild about switching on the connector type here (as opposed to dispatching to the connector itself) but
|
// I'm not wild about switching on the connector type here (as opposed to dispatching to the connector itself) but
|
||||||
// this felt like a compromise that allowed me to isolate connection logic without rewriting the entire source.
|
// this felt like a compromise that allowed me to isolate connection logic without rewriting the entire source.
|
||||||
switch c := s.connector.(type) {
|
switch c := s.connector.(type) {
|
||||||
case *appConnector:
|
case *appConnector:
|
||||||
if err := s.enumerateWithApp(ctx, c.InstallationClient()); err != nil {
|
if err := s.enumerateWithApp(ctx, c.InstallationClient(), noopReporter); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case *basicAuthConnector:
|
case *basicAuthConnector:
|
||||||
if err := s.enumerateBasicAuth(ctx); err != nil {
|
if err := s.enumerateBasicAuth(ctx, noopReporter); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case *tokenConnector:
|
case *tokenConnector:
|
||||||
if err := s.enumerateWithToken(ctx, c.IsGithubEnterprise()); err != nil {
|
if err := s.enumerateWithToken(ctx, c.IsGithubEnterprise(), noopReporter); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case *unauthenticatedConnector:
|
case *unauthenticatedConnector:
|
||||||
s.enumerateUnauthenticated(ctx)
|
s.enumerateUnauthenticated(ctx, noopReporter)
|
||||||
}
|
}
|
||||||
|
|
||||||
s.repos = make([]string, 0, s.filteredRepoCache.Count())
|
s.repos = make([]string, 0, s.filteredRepoCache.Count())
|
||||||
|
|
||||||
RepoLoop:
|
RepoLoop:
|
||||||
@@ -393,15 +424,17 @@ RepoLoop:
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Source) enumerateBasicAuth(ctx context.Context) error {
|
func (s *Source) enumerateBasicAuth(ctx context.Context, reporter sources.UnitReporter) error {
|
||||||
for _, org := range s.orgsCache.Keys() {
|
for _, org := range s.orgsCache.Keys() {
|
||||||
orgCtx := context.WithValue(ctx, "account", org)
|
orgCtx := context.WithValue(ctx, "account", org)
|
||||||
userType, err := s.getReposByOrgOrUser(ctx, org)
|
userType, err := s.getReposByOrgOrUser(ctx, org, reporter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
orgCtx.Logger().Error(err, "error fetching repos for org or user")
|
orgCtx.Logger().Error(err, "error fetching repos for org or user")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: This modifies s.memberCache but it doesn't look like
|
||||||
|
// we do anything with it.
|
||||||
if userType == organization && s.conn.ScanUsers {
|
if userType == organization && s.conn.ScanUsers {
|
||||||
if err := s.addMembersByOrg(ctx, org); err != nil {
|
if err := s.addMembersByOrg(ctx, org); err != nil {
|
||||||
orgCtx.Logger().Error(err, "Unable to add members by org")
|
orgCtx.Logger().Error(err, "Unable to add members by org")
|
||||||
@@ -412,14 +445,14 @@ func (s *Source) enumerateBasicAuth(ctx context.Context) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Source) enumerateUnauthenticated(ctx context.Context) {
|
func (s *Source) enumerateUnauthenticated(ctx context.Context, reporter sources.UnitReporter) {
|
||||||
if s.orgsCache.Count() > unauthGithubOrgRateLimt {
|
if s.orgsCache.Count() > unauthGithubOrgRateLimt {
|
||||||
ctx.Logger().Info("You may experience rate limiting when using the unauthenticated GitHub api. Consider using an authenticated scan instead.")
|
ctx.Logger().Info("You may experience rate limiting when using the unauthenticated GitHub api. Consider using an authenticated scan instead.")
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, org := range s.orgsCache.Keys() {
|
for _, org := range s.orgsCache.Keys() {
|
||||||
orgCtx := context.WithValue(ctx, "account", org)
|
orgCtx := context.WithValue(ctx, "account", org)
|
||||||
userType, err := s.getReposByOrgOrUser(ctx, org)
|
userType, err := s.getReposByOrgOrUser(ctx, org, reporter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
orgCtx.Logger().Error(err, "error fetching repos for org or user")
|
orgCtx.Logger().Error(err, "error fetching repos for org or user")
|
||||||
continue
|
continue
|
||||||
@@ -431,7 +464,7 @@ func (s *Source) enumerateUnauthenticated(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Source) enumerateWithToken(ctx context.Context, isGithubEnterprise bool) error {
|
func (s *Source) enumerateWithToken(ctx context.Context, isGithubEnterprise bool, reporter sources.UnitReporter) error {
|
||||||
ctx.Logger().V(1).Info("Enumerating with token")
|
ctx.Logger().V(1).Info("Enumerating with token")
|
||||||
|
|
||||||
var ghUser *github.User
|
var ghUser *github.User
|
||||||
@@ -450,10 +483,10 @@ func (s *Source) enumerateWithToken(ctx context.Context, isGithubEnterprise bool
|
|||||||
specificScope := len(s.repos) > 0 || s.orgsCache.Count() > 0
|
specificScope := len(s.repos) > 0 || s.orgsCache.Count() > 0
|
||||||
if !specificScope {
|
if !specificScope {
|
||||||
// Enumerate the user's orgs and repos if none were specified.
|
// Enumerate the user's orgs and repos if none were specified.
|
||||||
if err := s.getReposByUser(ctx, ghUser.GetLogin()); err != nil {
|
if err := s.getReposByUser(ctx, ghUser.GetLogin(), reporter); err != nil {
|
||||||
ctx.Logger().Error(err, "Unable to fetch repos for the current user", "user", ghUser.GetLogin())
|
ctx.Logger().Error(err, "Unable to fetch repos for the current user", "user", ghUser.GetLogin())
|
||||||
}
|
}
|
||||||
if err := s.addUserGistsToCache(ctx, ghUser.GetLogin()); err != nil {
|
if err := s.addUserGistsToCache(ctx, ghUser.GetLogin(), reporter); err != nil {
|
||||||
ctx.Logger().Error(err, "Unable to fetch gists for the current user", "user", ghUser.GetLogin())
|
ctx.Logger().Error(err, "Unable to fetch gists for the current user", "user", ghUser.GetLogin())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -469,7 +502,7 @@ func (s *Source) enumerateWithToken(ctx context.Context, isGithubEnterprise bool
|
|||||||
if len(s.orgsCache.Keys()) > 0 {
|
if len(s.orgsCache.Keys()) > 0 {
|
||||||
for _, org := range s.orgsCache.Keys() {
|
for _, org := range s.orgsCache.Keys() {
|
||||||
orgCtx := context.WithValue(ctx, "account", org)
|
orgCtx := context.WithValue(ctx, "account", org)
|
||||||
userType, err := s.getReposByOrgOrUser(ctx, org)
|
userType, err := s.getReposByOrgOrUser(ctx, org, reporter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
orgCtx.Logger().Error(err, "Unable to fetch repos for org or user")
|
orgCtx.Logger().Error(err, "Unable to fetch repos for org or user")
|
||||||
continue
|
continue
|
||||||
@@ -484,17 +517,17 @@ func (s *Source) enumerateWithToken(ctx context.Context, isGithubEnterprise bool
|
|||||||
|
|
||||||
if s.conn.ScanUsers && len(s.memberCache) > 0 {
|
if s.conn.ScanUsers && len(s.memberCache) > 0 {
|
||||||
ctx.Logger().Info("Fetching repos for org members", "org_count", s.orgsCache.Count(), "member_count", len(s.memberCache))
|
ctx.Logger().Info("Fetching repos for org members", "org_count", s.orgsCache.Count(), "member_count", len(s.memberCache))
|
||||||
s.addReposForMembers(ctx)
|
s.addReposForMembers(ctx, reporter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Source) enumerateWithApp(ctx context.Context, installationClient *github.Client) error {
|
func (s *Source) enumerateWithApp(ctx context.Context, installationClient *github.Client, reporter sources.UnitReporter) error {
|
||||||
// If no repos were provided, enumerate them.
|
// If no repos were provided, enumerate them.
|
||||||
if len(s.repos) == 0 {
|
if len(s.repos) == 0 {
|
||||||
if err := s.getReposByApp(ctx); err != nil {
|
if err := s.getReposByApp(ctx, reporter); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -505,12 +538,13 @@ func (s *Source) enumerateWithApp(ctx context.Context, installationClient *githu
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
ctx.Logger().Info("Scanning repos", "org_members", len(s.memberCache))
|
ctx.Logger().Info("Scanning repos", "org_members", len(s.memberCache))
|
||||||
|
// TODO: Replace loop below with a call to s.addReposForMembers(ctx, reporter)
|
||||||
for member := range s.memberCache {
|
for member := range s.memberCache {
|
||||||
logger := ctx.Logger().WithValues("member", member)
|
logger := ctx.Logger().WithValues("member", member)
|
||||||
if err := s.addUserGistsToCache(ctx, member); err != nil {
|
if err := s.addUserGistsToCache(ctx, member, reporter); err != nil {
|
||||||
logger.Error(err, "error fetching gists by user")
|
logger.Error(err, "error fetching gists by user")
|
||||||
}
|
}
|
||||||
if err := s.getReposByUser(ctx, member); err != nil {
|
if err := s.getReposByUser(ctx, member, reporter); err != nil {
|
||||||
logger.Error(err, "error fetching repos by user")
|
logger.Error(err, "error fetching repos by user")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -721,13 +755,13 @@ func (s *Source) handleRateLimit(ctx context.Context, errIn error) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Source) addReposForMembers(ctx context.Context) {
|
func (s *Source) addReposForMembers(ctx context.Context, reporter sources.UnitReporter) {
|
||||||
ctx.Logger().Info("Fetching repos from members", "members", len(s.memberCache))
|
ctx.Logger().Info("Fetching repos from members", "members", len(s.memberCache))
|
||||||
for member := range s.memberCache {
|
for member := range s.memberCache {
|
||||||
if err := s.addUserGistsToCache(ctx, member); err != nil {
|
if err := s.addUserGistsToCache(ctx, member, reporter); err != nil {
|
||||||
ctx.Logger().Info("Unable to fetch gists by user", "user", member, "error", err)
|
ctx.Logger().Info("Unable to fetch gists by user", "user", member, "error", err)
|
||||||
}
|
}
|
||||||
if err := s.getReposByUser(ctx, member); err != nil {
|
if err := s.getReposByUser(ctx, member, reporter); err != nil {
|
||||||
ctx.Logger().Info("Unable to fetch repos by user", "user", member, "error", err)
|
ctx.Logger().Info("Unable to fetch repos by user", "user", member, "error", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -735,7 +769,7 @@ func (s *Source) addReposForMembers(ctx context.Context) {
|
|||||||
|
|
||||||
// addUserGistsToCache collects all the gist urls for a given user,
|
// addUserGistsToCache collects all the gist urls for a given user,
|
||||||
// and adds them to the filteredRepoCache.
|
// and adds them to the filteredRepoCache.
|
||||||
func (s *Source) addUserGistsToCache(ctx context.Context, user string) error {
|
func (s *Source) addUserGistsToCache(ctx context.Context, user string, reporter sources.UnitReporter) error {
|
||||||
gistOpts := &github.GistListOptions{}
|
gistOpts := &github.GistListOptions{}
|
||||||
logger := ctx.Logger().WithValues("user", user)
|
logger := ctx.Logger().WithValues("user", user)
|
||||||
|
|
||||||
@@ -751,6 +785,9 @@ func (s *Source) addUserGistsToCache(ctx context.Context, user string) error {
|
|||||||
for _, gist := range gists {
|
for _, gist := range gists {
|
||||||
s.filteredRepoCache.Set(gist.GetID(), gist.GetGitPullURL())
|
s.filteredRepoCache.Set(gist.GetID(), gist.GetGitPullURL())
|
||||||
s.cacheGistInfo(gist)
|
s.cacheGistInfo(gist)
|
||||||
|
if err := reporter.UnitOk(ctx, GistUnit{name: gist.GetID(), url: gist.GetGitPullURL()}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if res == nil || res.NextPage == 0 {
|
if res == nil || res.NextPage == 0 {
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
|
||||||
"github.com/kylelemons/godebug/pretty"
|
"github.com/kylelemons/godebug/pretty"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"google.golang.org/protobuf/types/known/anypb"
|
"google.golang.org/protobuf/types/known/anypb"
|
||||||
@@ -58,12 +57,11 @@ func TestSource_Token(t *testing.T) {
|
|||||||
|
|
||||||
s := Source{
|
s := Source{
|
||||||
conn: src,
|
conn: src,
|
||||||
log: logr.Discard(),
|
|
||||||
memberCache: map[string]struct{}{},
|
memberCache: map[string]struct{}{},
|
||||||
repoInfoCache: newRepoInfoCache(),
|
repoInfoCache: newRepoInfoCache(),
|
||||||
}
|
}
|
||||||
s.Init(ctx, "github integration test source", 0, 0, false, conn, 1)
|
s.Init(ctx, "github integration test source", 0, 0, false, conn, 1)
|
||||||
s.filteredRepoCache = s.newFilteredRepoCache(memory.New[string](), nil, nil)
|
s.filteredRepoCache = s.newFilteredRepoCache(ctx, memory.New[string](), nil, nil)
|
||||||
|
|
||||||
err = s.enumerateWithApp(ctx, s.connector.(*appConnector).InstallationClient())
|
err = s.enumerateWithApp(ctx, s.connector.(*appConnector).InstallationClient())
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ func TestAddReposByOrg(t *testing.T) {
|
|||||||
Repositories: nil,
|
Repositories: nil,
|
||||||
IgnoreRepos: []string{"secret/super-*-repo2"},
|
IgnoreRepos: []string{"secret/super-*-repo2"},
|
||||||
})
|
})
|
||||||
err := s.getReposByOrg(context.Background(), "super-secret-org")
|
err := s.getReposByOrg(context.Background(), "super-secret-org", noopReporter())
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, s.filteredRepoCache.Count())
|
assert.Equal(t, 1, s.filteredRepoCache.Count())
|
||||||
ok := s.filteredRepoCache.Exists("super-secret-repo")
|
ok := s.filteredRepoCache.Exists("super-secret-repo")
|
||||||
@@ -127,7 +127,7 @@ func TestAddReposByOrg_IncludeRepos(t *testing.T) {
|
|||||||
IncludeRepos: []string{"super-secret-org/super*"},
|
IncludeRepos: []string{"super-secret-org/super*"},
|
||||||
Organizations: []string{"super-secret-org"},
|
Organizations: []string{"super-secret-org"},
|
||||||
})
|
})
|
||||||
err := s.getReposByOrg(context.Background(), "super-secret-org")
|
err := s.getReposByOrg(context.Background(), "super-secret-org", noopReporter())
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 2, s.filteredRepoCache.Count())
|
assert.Equal(t, 2, s.filteredRepoCache.Count())
|
||||||
ok := s.filteredRepoCache.Exists("super-secret-org/super-secret-repo")
|
ok := s.filteredRepoCache.Exists("super-secret-org/super-secret-repo")
|
||||||
@@ -155,7 +155,7 @@ func TestAddReposByUser(t *testing.T) {
|
|||||||
},
|
},
|
||||||
IgnoreRepos: []string{"super-secret-user/super-secret-repo2"},
|
IgnoreRepos: []string{"super-secret-user/super-secret-repo2"},
|
||||||
})
|
})
|
||||||
err := s.getReposByUser(context.Background(), "super-secret-user")
|
err := s.getReposByUser(context.Background(), "super-secret-user", noopReporter())
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, s.filteredRepoCache.Count())
|
assert.Equal(t, 1, s.filteredRepoCache.Count())
|
||||||
ok := s.filteredRepoCache.Exists("super-secret-user/super-secret-repo")
|
ok := s.filteredRepoCache.Exists("super-secret-user/super-secret-repo")
|
||||||
@@ -173,7 +173,7 @@ func TestAddGistsByUser(t *testing.T) {
|
|||||||
JSON([]map[string]string{{"id": "aa5a315d61ae9438b18d", "git_pull_url": "https://gist.github.com/aa5a315d61ae9438b18d.git"}})
|
JSON([]map[string]string{{"id": "aa5a315d61ae9438b18d", "git_pull_url": "https://gist.github.com/aa5a315d61ae9438b18d.git"}})
|
||||||
|
|
||||||
s := initTestSource(&sourcespb.GitHub{Credential: &sourcespb.GitHub_Unauthenticated{}})
|
s := initTestSource(&sourcespb.GitHub{Credential: &sourcespb.GitHub_Unauthenticated{}})
|
||||||
err := s.addUserGistsToCache(context.Background(), "super-secret-user")
|
err := s.addUserGistsToCache(context.Background(), "super-secret-user", noopReporter())
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, s.filteredRepoCache.Count())
|
assert.Equal(t, 1, s.filteredRepoCache.Count())
|
||||||
ok := s.filteredRepoCache.Exists("aa5a315d61ae9438b18d")
|
ok := s.filteredRepoCache.Exists("aa5a315d61ae9438b18d")
|
||||||
@@ -265,7 +265,7 @@ func TestAddReposByApp(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
s := initTestSource(&sourcespb.GitHub{Credential: &sourcespb.GitHub_Unauthenticated{}})
|
s := initTestSource(&sourcespb.GitHub{Credential: &sourcespb.GitHub_Unauthenticated{}})
|
||||||
err := s.getReposByApp(context.Background())
|
err := s.getReposByApp(context.Background(), noopReporter())
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 2, s.filteredRepoCache.Count())
|
assert.Equal(t, 2, s.filteredRepoCache.Count())
|
||||||
ok := s.filteredRepoCache.Exists("ssr1")
|
ok := s.filteredRepoCache.Exists("ssr1")
|
||||||
@@ -419,7 +419,7 @@ func TestEnumerateUnauthenticated(t *testing.T) {
|
|||||||
s.orgsCache = memory.New[string]()
|
s.orgsCache = memory.New[string]()
|
||||||
s.orgsCache.Set("super-secret-org", "super-secret-org")
|
s.orgsCache.Set("super-secret-org", "super-secret-org")
|
||||||
//s.enumerateUnauthenticated(context.Background(), apiEndpoint)
|
//s.enumerateUnauthenticated(context.Background(), apiEndpoint)
|
||||||
s.enumerateUnauthenticated(context.Background())
|
s.enumerateUnauthenticated(context.Background(), noopReporter())
|
||||||
assert.Equal(t, 1, s.filteredRepoCache.Count())
|
assert.Equal(t, 1, s.filteredRepoCache.Count())
|
||||||
ok := s.filteredRepoCache.Exists("super-secret-org/super-secret-repo")
|
ok := s.filteredRepoCache.Exists("super-secret-org/super-secret-repo")
|
||||||
assert.True(t, ok)
|
assert.True(t, ok)
|
||||||
@@ -458,7 +458,7 @@ func TestEnumerateWithToken(t *testing.T) {
|
|||||||
Token: "token",
|
Token: "token",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
err := s.enumerateWithToken(context.Background(), false)
|
err := s.enumerateWithToken(context.Background(), false, noopReporter())
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 2, s.filteredRepoCache.Count())
|
assert.Equal(t, 2, s.filteredRepoCache.Count())
|
||||||
ok := s.filteredRepoCache.Exists("super-secret-user/super-secret-repo")
|
ok := s.filteredRepoCache.Exists("super-secret-user/super-secret-repo")
|
||||||
@@ -502,7 +502,7 @@ func BenchmarkEnumerateWithToken(b *testing.B) {
|
|||||||
|
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = s.enumerateWithToken(context.Background(), false)
|
_ = s.enumerateWithToken(context.Background(), false, noopReporter())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -660,7 +660,7 @@ func TestEnumerateWithToken_IncludeRepos(t *testing.T) {
|
|||||||
})
|
})
|
||||||
s.repos = []string{"some-special-repo"}
|
s.repos = []string{"some-special-repo"}
|
||||||
|
|
||||||
err := s.enumerateWithToken(context.Background(), false)
|
err := s.enumerateWithToken(context.Background(), false, noopReporter())
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(s.repos))
|
assert.Equal(t, 1, len(s.repos))
|
||||||
assert.Equal(t, []string{"some-special-repo"}, s.repos)
|
assert.Equal(t, []string{"some-special-repo"}, s.repos)
|
||||||
@@ -693,7 +693,7 @@ func TestEnumerateWithApp(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
err := s.enumerateWithApp(context.Background(), s.connector.(*appConnector).InstallationClient())
|
err := s.enumerateWithApp(context.Background(), s.connector.(*appConnector).InstallationClient(), noopReporter())
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 0, len(s.repos))
|
assert.Equal(t, 0, len(s.repos))
|
||||||
assert.False(t, gock.HasUnmatchedRequest())
|
assert.False(t, gock.HasUnmatchedRequest())
|
||||||
@@ -908,3 +908,11 @@ func Test_ScanMultipleTargets_MultipleErrors(t *testing.T) {
|
|||||||
assert.ElementsMatch(t, got, want)
|
assert.ElementsMatch(t, got, want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func noopReporter() sources.UnitReporter {
|
||||||
|
return sources.VisitorReporter{
|
||||||
|
VisitUnit: func(context.Context, sources.SourceUnit) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+15
-12
@@ -14,6 +14,7 @@ import (
|
|||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/context"
|
"github.com/trufflesecurity/trufflehog/v3/pkg/context"
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/giturl"
|
"github.com/trufflesecurity/trufflehog/v3/pkg/giturl"
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/source_metadatapb"
|
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/source_metadatapb"
|
||||||
|
"github.com/trufflesecurity/trufflehog/v3/pkg/sources"
|
||||||
)
|
)
|
||||||
|
|
||||||
type repoInfoCache struct {
|
type repoInfoCache struct {
|
||||||
@@ -76,8 +77,8 @@ func (s *Source) appListReposWrapper(ctx context.Context, _ string, opts repoLis
|
|||||||
return nil, res, err
|
return nil, res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Source) getReposByApp(ctx context.Context) error {
|
func (s *Source) getReposByApp(ctx context.Context, reporter sources.UnitReporter) error {
|
||||||
return s.processRepos(ctx, "", s.appListReposWrapper, &appListOptions{
|
return s.processRepos(ctx, "", reporter, s.appListReposWrapper, &appListOptions{
|
||||||
ListOptions: github.ListOptions{
|
ListOptions: github.ListOptions{
|
||||||
PerPage: defaultPagination,
|
PerPage: defaultPagination,
|
||||||
},
|
},
|
||||||
@@ -96,8 +97,8 @@ func (s *Source) userListReposWrapper(ctx context.Context, user string, opts rep
|
|||||||
return s.connector.APIClient().Repositories.ListByUser(ctx, user, &opts.(*userListOptions).RepositoryListByUserOptions)
|
return s.connector.APIClient().Repositories.ListByUser(ctx, user, &opts.(*userListOptions).RepositoryListByUserOptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Source) getReposByUser(ctx context.Context, user string) error {
|
func (s *Source) getReposByUser(ctx context.Context, user string, reporter sources.UnitReporter) error {
|
||||||
return s.processRepos(ctx, user, s.userListReposWrapper, &userListOptions{
|
return s.processRepos(ctx, user, reporter, s.userListReposWrapper, &userListOptions{
|
||||||
RepositoryListByUserOptions: github.RepositoryListByUserOptions{
|
RepositoryListByUserOptions: github.RepositoryListByUserOptions{
|
||||||
ListOptions: github.ListOptions{
|
ListOptions: github.ListOptions{
|
||||||
PerPage: defaultPagination,
|
PerPage: defaultPagination,
|
||||||
@@ -119,8 +120,8 @@ func (s *Source) orgListReposWrapper(ctx context.Context, org string, opts repoL
|
|||||||
return s.connector.APIClient().Repositories.ListByOrg(ctx, org, &opts.(*orgListOptions).RepositoryListByOrgOptions)
|
return s.connector.APIClient().Repositories.ListByOrg(ctx, org, &opts.(*orgListOptions).RepositoryListByOrgOptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Source) getReposByOrg(ctx context.Context, org string) error {
|
func (s *Source) getReposByOrg(ctx context.Context, org string, reporter sources.UnitReporter) error {
|
||||||
return s.processRepos(ctx, org, s.orgListReposWrapper, &orgListOptions{
|
return s.processRepos(ctx, org, reporter, s.orgListReposWrapper, &orgListOptions{
|
||||||
RepositoryListByOrgOptions: github.RepositoryListByOrgOptions{
|
RepositoryListByOrgOptions: github.RepositoryListByOrgOptions{
|
||||||
ListOptions: github.ListOptions{
|
ListOptions: github.ListOptions{
|
||||||
PerPage: defaultPagination,
|
PerPage: defaultPagination,
|
||||||
@@ -145,11 +146,11 @@ const (
|
|||||||
organization
|
organization
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *Source) getReposByOrgOrUser(ctx context.Context, name string) (userType, error) {
|
func (s *Source) getReposByOrgOrUser(ctx context.Context, name string, reporter sources.UnitReporter) (userType, error) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
// List repositories for the organization |name|.
|
// List repositories for the organization |name|.
|
||||||
err = s.getReposByOrg(ctx, name)
|
err = s.getReposByOrg(ctx, name, reporter)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return organization, nil
|
return organization, nil
|
||||||
} else if !isGitHub404Error(err) {
|
} else if !isGitHub404Error(err) {
|
||||||
@@ -157,9 +158,9 @@ func (s *Source) getReposByOrgOrUser(ctx context.Context, name string) (userType
|
|||||||
}
|
}
|
||||||
|
|
||||||
// List repositories for the user |name|.
|
// List repositories for the user |name|.
|
||||||
err = s.getReposByUser(ctx, name)
|
err = s.getReposByUser(ctx, name, reporter)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if err := s.addUserGistsToCache(ctx, name); err != nil {
|
if err := s.addUserGistsToCache(ctx, name, reporter); err != nil {
|
||||||
ctx.Logger().Error(err, "Unable to add user to cache")
|
ctx.Logger().Error(err, "Unable to add user to cache")
|
||||||
}
|
}
|
||||||
return user, nil
|
return user, nil
|
||||||
@@ -180,7 +181,7 @@ func isGitHub404Error(err error) bool {
|
|||||||
return ghErr.Response.StatusCode == http.StatusNotFound
|
return ghErr.Response.StatusCode == http.StatusNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Source) processRepos(ctx context.Context, target string, listRepos repoLister, listOpts repoListOptions) error {
|
func (s *Source) processRepos(ctx context.Context, target string, reporter sources.UnitReporter, listRepos repoLister, listOpts repoListOptions) error {
|
||||||
logger := ctx.Logger().WithValues("target", target)
|
logger := ctx.Logger().WithValues("target", target)
|
||||||
opts := listOpts.getListOptions()
|
opts := listOpts.getListOptions()
|
||||||
|
|
||||||
@@ -215,8 +216,10 @@ func (s *Source) processRepos(ctx context.Context, target string, listRepos repo
|
|||||||
repoName, repoURL := r.GetFullName(), r.GetCloneURL()
|
repoName, repoURL := r.GetFullName(), r.GetCloneURL()
|
||||||
s.totalRepoSize += r.GetSize()
|
s.totalRepoSize += r.GetSize()
|
||||||
s.filteredRepoCache.Set(repoName, repoURL)
|
s.filteredRepoCache.Set(repoName, repoURL)
|
||||||
|
|
||||||
s.cacheRepoInfo(r)
|
s.cacheRepoInfo(r)
|
||||||
|
if err := reporter.UnitOk(ctx, RepoUnit{name: repoName, url: repoURL}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
logger.V(3).Info("repo attributes", "name", repoName, "kb_size", r.GetSize(), "repo_url", repoURL)
|
logger.V(3).Info("repo attributes", "name", repoName, "kb_size", r.GetSize(), "repo_url", repoURL)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user