feat: add excludeRepos support to GithubOrgReader (#476)

* feat: add excludeRepos support to GithubOrgReader

* feat: add excludeRepos support to GithubOrgReader

* Syntax changes

* fix: excluded repo variable declartion

* fix: scan command to include excluded repo config

---------

Co-authored-by: abhisek <abhisek.datta@gmail.com>
This commit is contained in:
infosecwonderland 2025-04-28 17:33:54 +08:00 committed by GitHub
parent e90756d5a3
commit eebae09e82
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 71 additions and 0 deletions

View File

@ -21,6 +21,7 @@ type GithubOrgReaderConfig struct {
IncludeArchived bool IncludeArchived bool
MaxRepositories int MaxRepositories int
SkipDependencyGraphAPI bool SkipDependencyGraphAPI bool
ExcludeRepos []string
} }
type githubOrgReader struct { type githubOrgReader struct {
@ -127,7 +128,14 @@ func (p *githubOrgReader) handleRepositoryBatch(repositories []*github.Repositor
handler PackageManifestHandlerFn, handler PackageManifestHandlerFn,
) error { ) error {
var repoUrls []string var repoUrls []string
for _, repo := range repositories { for _, repo := range repositories {
fullName := repo.GetFullName()
if githubIsExcludedRepo(fullName, p.config.ExcludeRepos) {
logger.Infof("Skipping excluded repo: %s", fullName)
continue
}
breach := p.withIncrementedRepoCount(func() { breach := p.withIncrementedRepoCount(func() {
repoUrls = append(repoUrls, repo.GetCloneURL()) repoUrls = append(repoUrls, repo.GetCloneURL())
}) })
@ -171,3 +179,20 @@ func githubOrgFromURL(githubUrl string) (string, error) {
return parts[1], nil return parts[1], nil
} }
// To exclude specific repo using github org scanner
func githubIsExcludedRepo(repoName string, excludedRepositories []string) bool {
if len(excludedRepositories) == 0 {
return false
}
logger.Debugf("Checking if repo %s is excluded", repoName)
for _, ex := range excludedRepositories {
if strings.TrimSpace(repoName) == strings.TrimSpace(ex) {
return true
}
}
return false
}

View File

@ -77,4 +77,46 @@ func TestGithubOrgReader(t *testing.T) {
} }
}) })
} }
}
func TestGithubIsExcludedRepo(t *testing.T) {
cases := []struct {
name string
fullName string
excluded []string
expectedVal bool
}{
{
name: "no excluded repo configured",
fullName: "x/y",
excluded: []string{},
expectedVal: false,
},
{
name: "match excluded",
fullName: "x/y",
excluded: []string{"y/z", "x/y"},
expectedVal: true,
},
{
name: "match with ignore whitespace",
fullName: "x/y",
excluded: []string{" x/y ", "b", "c"},
expectedVal: true,
},
{
name: "no match",
fullName: "x/u",
excluded: []string{"x/y"},
expectedVal: false,
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
ret := githubIsExcludedRepo(tc.fullName, tc.excluded)
assert.Equal(t, tc.expectedVal, ret)
})
}
} }

View File

@ -42,6 +42,7 @@ var (
githubRepoUrls []string githubRepoUrls []string
githubOrgUrl string githubOrgUrl string
githubOrgMaxRepositories int githubOrgMaxRepositories int
githubOrgExcludedRepos []string
githubSkipDependencyGraphAPI bool githubSkipDependencyGraphAPI bool
scanExclude []string scanExclude []string
transitiveAnalysis bool transitiveAnalysis bool
@ -134,6 +135,8 @@ func newScanCommand() *cobra.Command {
"Github organization URL (Example: https://github.com/safedep)") "Github organization URL (Example: https://github.com/safedep)")
cmd.Flags().IntVarP(&githubOrgMaxRepositories, "github-org-max-repo", "", 1000, cmd.Flags().IntVarP(&githubOrgMaxRepositories, "github-org-max-repo", "", 1000,
"Maximum number of repositories to process for the Github Org") "Maximum number of repositories to process for the Github Org")
cmd.Flags().StringArrayVarP(&githubOrgExcludedRepos, "github-org-exclude-repos", "", []string{},
"Comma-separated list of GitHub repos to exclude during org scan (format: org/repo1,org/repo2)")
cmd.Flags().BoolVarP(&githubSkipDependencyGraphAPI, "skip-github-dependency-graph-api", "", false, cmd.Flags().BoolVarP(&githubSkipDependencyGraphAPI, "skip-github-dependency-graph-api", "", false,
"Do not use GitHub Dependency Graph API to fetch dependencies") "Do not use GitHub Dependency Graph API to fetch dependencies")
cmd.Flags().StringVarP(&lockfileAs, "lockfile-as", "", "", cmd.Flags().StringVarP(&lockfileAs, "lockfile-as", "", "",
@ -365,6 +368,7 @@ func internalStartScan() error {
IncludeArchived: false, IncludeArchived: false,
MaxRepositories: githubOrgMaxRepositories, MaxRepositories: githubOrgMaxRepositories,
SkipDependencyGraphAPI: githubSkipDependencyGraphAPI, SkipDependencyGraphAPI: githubSkipDependencyGraphAPI,
ExcludeRepos: githubOrgExcludedRepos,
}) })
} else if len(purlSpec) > 0 { } else if len(purlSpec) > 0 {
analytics.TrackCommandScanPurlScan() analytics.TrackCommandScanPurlScan()