Skip to content

Commit 4bdf280

Browse files
committed
Allow inaccessible repos, logging and adjust page limit of 100
1 parent 06c7c7c commit 4bdf280

4 files changed

Lines changed: 67 additions & 14 deletions

File tree

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ dist/
44
cf-plugin-local-ssh
55
plugin
66
.env
7-
.envrc
7+
.envrc
8+
plugin-*

README.MD renamed to README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ To authenticate this plugin, you must provide a token which has at minimum the f
1313

1414
## Integration testing
1515

16-
This plugin contains unit tests as well as integration tests.
16+
This plugin contains unit tests as well as integration tests.
1717

1818
The Integration tests need a GitHub token to call to the GitHub API.
1919

@@ -33,9 +33,9 @@ package compliance_framework.deny_critical_severity
3333

3434
## Releases
3535

36-
This plugin is released using goreleaser to build binaries, and GOOCI to upload artifacts to OCI,
37-
which will ensure a binary is built for most OS and Architecture combinations.
36+
This plugin is released using goreleaser to build binaries, and GOOCI to upload artifacts to OCI,
37+
which will ensure a binary is built for most OS and Architecture combinations.
3838

3939
You can find the binaries on each release of this plugin in the GitHub releases page.
4040

41-
You can find the OCI implementations in the GitHub Packages page.
41+
You can find the OCI implementations in the GitHub Packages page.

examples/README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
# Example output from Local SSH plugin
1+
# Example output from Dependabot plugin
22

3-
In this folder you'll find example data and policies for the Local SSH Plugin
3+
In this folder you'll find example data and policies for the Dependabot Plugin
44

55
## Data
66

7-
In `input/` you'll find an example of the data that is output from the plugin and passed to the policy files. This is
8-
what you will write policies against to check for compliance.
7+
In `input/` you'll find an example of the data that is output from the plugin and passed to the policy files. This is
8+
what you will write policies against to check for compliance.
99

1010
These will be defined as `input` in Rego policies.
1111

main.go

Lines changed: 57 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ func (l *DependabotPlugin) Eval(req *proto.EvalRequest, apiHelper runner.ApiHelp
6060
}
6161

6262
done := false
63+
// Track permission issues during alert collection
64+
reposAlertsPermissionDenied := make([]string, 0)
6365

6466
for !done {
6567
select {
@@ -79,6 +81,11 @@ func (l *DependabotPlugin) Eval(req *proto.EvalRequest, apiHelper runner.ApiHelp
7981

8082
alerts, err := l.FetchRepositoryDependabotAlerts(ctx, repo)
8183
if err != nil {
84+
if isPermissionError(err) {
85+
l.logger.Warn("Skipping repository due to insufficient permissions for alerts fetch", "repo", repo.GetFullName(), "error", err)
86+
reposAlertsPermissionDenied = append(reposAlertsPermissionDenied, repo.GetFullName())
87+
continue
88+
}
8289
return &proto.EvalResponse{
8390
Status: proto.ExecutionStatus_FAILURE,
8491
}, err
@@ -107,6 +114,10 @@ func (l *DependabotPlugin) Eval(req *proto.EvalRequest, apiHelper runner.ApiHelp
107114
}
108115
}
109116

117+
if len(reposAlertsPermissionDenied) > 0 {
118+
l.logger.Info("Repositories skipped due to insufficient permissions (alerts)", "count", len(reposAlertsPermissionDenied), "repos", reposAlertsPermissionDenied)
119+
}
120+
110121
return &proto.EvalResponse{
111122
Status: proto.ExecutionStatus_SUCCESS,
112123
}, nil
@@ -124,7 +135,7 @@ func (l *DependabotPlugin) FetchRepositoryDependabotAlerts(ctx context.Context,
124135
alerts, _, err := l.githubClient.Dependabot.ListRepoAlerts(ctx, repo.GetOwner().GetLogin(), repo.GetName(), &github.ListAlertsOptions{
125136
ListOptions: github.ListOptions{
126137
Page: 1,
127-
PerPage: 200,
138+
PerPage: 100,
128139
},
129140
ListCursorOptions: github.ListCursorOptions{},
130141
})
@@ -139,6 +150,10 @@ func (l *DependabotPlugin) FetchRepositories(ctx context.Context) (<-chan *githu
139150
defer close(errs)
140151
page := 1
141152
done := false
153+
// Tracking for logging visibility
154+
emittedRepos := make([]string, 0)
155+
noPermissionRepos := make([]string, 0)
156+
archivedSkipped := 0
142157
for !done {
143158
l.logger.Trace("Fetching repositories from Github API")
144159
repos, _, err := l.githubClient.Repositories.ListByOrg(ctx, *l.config.Organization, &github.RepositoryListByOrgOptions{
@@ -153,14 +168,25 @@ func (l *DependabotPlugin) FetchRepositories(ctx context.Context) (<-chan *githu
153168
break
154169
}
155170
for _, repo := range repos {
171+
if repo.GetArchived() {
172+
archivedSkipped++
173+
continue
174+
}
175+
156176
alertsEnabled, _, err := l.githubClient.Repositories.GetVulnerabilityAlerts(ctx, repo.GetOwner().GetLogin(), repo.GetName())
157177
if err != nil {
178+
if isPermissionError(err) {
179+
l.logger.Warn("Skipping repository due to insufficient permissions for vulnerability alerts check", "repo", repo.GetFullName(), "error", err)
180+
noPermissionRepos = append(noPermissionRepos, repo.GetFullName())
181+
continue
182+
}
158183
errs <- err
159184
done = true
160185
break
161186
}
162-
if !repo.GetArchived() && alertsEnabled {
187+
if alertsEnabled {
163188
repositories <- repo
189+
emittedRepos = append(emittedRepos, repo.GetFullName())
164190
}
165191
}
166192
page++
@@ -169,6 +195,14 @@ func (l *DependabotPlugin) FetchRepositories(ctx context.Context) (<-chan *githu
169195
break
170196
}
171197
}
198+
// Emit a summary for engineers to understand visibility
199+
l.logger.Info("Repository enumeration summary", "emitted", len(emittedRepos), "skipped_permissions", len(noPermissionRepos), "skipped_archived", archivedSkipped)
200+
if len(emittedRepos) > 0 {
201+
l.logger.Debug("Repositories with sufficient permissions (and alerts enabled)", "repos", emittedRepos)
202+
}
203+
if len(noPermissionRepos) > 0 {
204+
l.logger.Info("Repositories without sufficient permissions", "repos", noPermissionRepos)
205+
}
172206
}()
173207
return repositories, errs
174208
}
@@ -195,13 +229,13 @@ func (l *DependabotPlugin) EvaluatePolicies(ctx context.Context, repo *github.Re
195229
Props: nil,
196230
},
197231
{
198-
Title: "Continuous Compliance Framework - Local SSH Plugin",
232+
Title: "Continuous Compliance Framework - Dependabot Plugin",
199233
Type: "tool",
200234
Links: []*proto.Link{
201235
{
202-
Href: "https://github.com/compliance-framework/plugin-local-ssh",
236+
Href: "https://github.com/compliance-framework/plugin-dependabot",
203237
Rel: policyManager.Pointer("reference"),
204-
Text: policyManager.Pointer("The Continuous Compliance Framework' Local SSH Plugin"),
238+
Text: policyManager.Pointer("The Continuous Compliance Framework Dependabot Plugin"),
205239
},
206240
},
207241
Props: nil,
@@ -305,6 +339,24 @@ func (l *DependabotPlugin) EvaluatePolicies(ctx context.Context, repo *github.Re
305339
return evidences, accumulatedErrors
306340
}
307341

342+
// isPermissionError returns true if the error from the GitHub client indicates
343+
// a permissions or visibility issue (e.g., 401/403/404).
344+
func isPermissionError(err error) bool {
345+
if err == nil {
346+
return false
347+
}
348+
var ger *github.ErrorResponse
349+
if errors.As(err, &ger) {
350+
if ger.Response != nil {
351+
switch ger.Response.StatusCode {
352+
case 401, 403, 404:
353+
return true
354+
}
355+
}
356+
}
357+
return false
358+
}
359+
308360
func main() {
309361
logger := hclog.New(&hclog.LoggerOptions{
310362
Level: hclog.Debug,

0 commit comments

Comments
 (0)