Skip to content

Commit

Permalink
feat: add GitHub code scanning alerts to CVE metric (#387)
Browse files Browse the repository at this point in the history
--------

Signed-off-by: ahmada-liatrio <[email protected]>
Co-authored-by: Adriel Perkins <[email protected]>
Co-authored-by: Adriel Perkins <[email protected]>
  • Loading branch information
3 people committed May 1, 2024
1 parent f8b1351 commit 2d152c9
Show file tree
Hide file tree
Showing 6 changed files with 422 additions and 111 deletions.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -197,10 +197,15 @@ query getPullRequestData(
}
}

query getRepoCVEs($owner: String!, $repo: String!) {
query getRepoCVEs(
$owner: String!,
$repo: String!,
# @genqlient(pointer: true)
$alertCursor: String
) {
repository(owner: $owner, name: $repo, ) {
# @genqlient(typename: "VulnerabilityAlerts")
vulnerabilityAlerts(first: 100, states: OPEN) {
vulnerabilityAlerts(first: 100, states: OPEN, after: $alertCursor) {
pageInfo {
hasNextPage
endCursor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ func (ghs *githubScraper) scrape(ctx context.Context) (pmetric.Metrics, error) {

// When enabled, process any CVEs for the repository
if ghs.cfg.Metrics.GitRepositoryCveCount.Enabled {
cves, err := ghs.getCVEs(ctx, genClient, name)
cves, err := ghs.getCVEs(ctx, genClient, restClient, name)
if err != nil {
ghs.logger.Sugar().Errorf("error %v getting cves from repo %s", zap.Error(err), name)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,8 @@ func TestScrape(t *testing.T) {
},
responseCode: http.StatusOK,
},
cveResponse: cveResponse{
cves: []VulnerabilityAlerts{
depBotAlertResponse: depBotAlertResponse{
depBotsAlerts: []VulnerabilityAlerts{
{
Nodes: []CVENode{
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"math"
"net/url"
"strings"
"time"

"github.com/liatrio/liatrio-otel-collector/receiver/gitproviderreceiver/internal/metadata"
Expand Down Expand Up @@ -311,19 +312,78 @@ func getAge(start time.Time, end time.Time) int64 {

func (ghs *githubScraper) getCVEs(
ctx context.Context,
client graphql.Client,
gClient graphql.Client,
rClient *github.Client,
repo string,
) (map[metadata.AttributeCveSeverity]int64, error) {
c, err := getRepoCVEs(ctx, client, ghs.cfg.GitHubOrg, repo)
if err != nil {
return nil, err
d := ghs.getDepBotAlerts(ctx, gClient, repo)
c := ghs.getCodeScanAlerts(ctx, rClient, repo)

return mapSeverities(d, c), nil
}

func (ghs *githubScraper) getDepBotAlerts(
ctx context.Context,
gClient graphql.Client,
repo string,
) []CVENode {

var alerts []CVENode
var cursor *string

for hasNextPage := true; hasNextPage; {
a, err := getRepoCVEs(ctx, gClient, ghs.cfg.GitHubOrg, repo, cursor)

if err != nil {
ghs.logger.Sugar().Errorf("error %v getting dependabot alerts from repo %s", zap.Error(err), repo)
return nil
}

hasNextPage = a.Repository.VulnerabilityAlerts.PageInfo.HasNextPage
cursor = &a.Repository.VulnerabilityAlerts.PageInfo.EndCursor
alerts = append(alerts, a.Repository.VulnerabilityAlerts.Nodes...)

}

return mapSeverities(c.GetRepository()), nil
return alerts
}

// Get the Code Scanning Alerts count for a repository via the REST API
func (ghs *githubScraper) getCodeScanAlerts(
ctx context.Context,
rClient *github.Client,
repo string,
) []*github.Alert {
var alerts []*github.Alert

// Options for Pagination support, default from GitHub was 30. Max is 100
// https://docs.github.com/en/rest/code-scanning/code-scanning?apiVersion=2022-11-28
opt := &github.AlertListOptions{
ListOptions: github.ListOptions{PerPage: 50},
State: "open",
}

for {
a, resp, err := rClient.CodeScanning.ListAlertsForRepo(ctx, ghs.cfg.GitHubOrg, repo, opt)
if err != nil {
ghs.logger.Sugar().Errorf("error getting code scanning alerts from repo", zap.Error(err))
return nil
}

alerts = append(alerts, a...)
if resp.NextPage == 0 {
break
}

opt.ListOptions.Page = resp.NextPage
}

return alerts
}

func mapSeverities(
n getRepoCVEsRepository,
nodes []CVENode,
alerts []*github.Alert,
) map[metadata.AttributeCveSeverity]int64 {

// Allows us to map the "MODERATE" to the conventional "medium" and support
Expand All @@ -332,12 +392,19 @@ func mapSeverities(
"CRITICAL": metadata.AttributeCveSeverityCritical,
"HIGH": metadata.AttributeCveSeverityHigh,
"MODERATE": metadata.AttributeCveSeverityMedium,
"MEDIUM": metadata.AttributeCveSeverityMedium,
"LOW": metadata.AttributeCveSeverityLow,
}
m := make(map[metadata.AttributeCveSeverity]int64)

for _, node := range n.VulnerabilityAlerts.Nodes {
if val, found := mapping[string(node.SecurityVulnerability.Severity)]; found {
for _, node := range nodes {
if val, found := mapping[strings.ToUpper(string(node.SecurityVulnerability.Severity))]; found {
m[val]++
}
}

for _, alert := range alerts {
if val, found := mapping[strings.ToUpper(*alert.Rule.SecuritySeverityLevel)]; found {
m[val]++
}
}
Expand Down
Loading

0 comments on commit 2d152c9

Please sign in to comment.