Skip to content

Commit

Permalink
Add table github_dependabot_alert
Browse files Browse the repository at this point in the history
  • Loading branch information
francois2metz committed Nov 5, 2022
1 parent 3678448 commit 9540e19
Show file tree
Hide file tree
Showing 2 changed files with 235 additions and 0 deletions.
1 change: 1 addition & 0 deletions github/plugin.go
Expand Up @@ -27,6 +27,7 @@ func Plugin(ctx context.Context) *plugin.Plugin {
"github_commit": tableGitHubCommit(ctx),
"github_community_profile": tableGitHubCommunityProfile(ctx),
"github_code_owner": tableGitHubCodeOwner(),
"github_dependabot_alert": tableGitHubDependabotAlert(),
"github_gist": tableGitHubGist(),
"github_gitignore": tableGitHubGitignore(),
"github_issue": tableGitHubIssue(),
Expand Down
234 changes: 234 additions & 0 deletions github/table_github_dependabot_alert.go
@@ -0,0 +1,234 @@
package github

import (
"context"

"github.com/google/go-github/v45/github"
"github.com/turbot/steampipe-plugin-sdk/v4/grpc/proto"
"github.com/turbot/steampipe-plugin-sdk/v4/plugin"
"github.com/turbot/steampipe-plugin-sdk/v4/plugin/transform"
)

//// TABLE DEFINITION

func tableGitHubDependabotAlert() *plugin.Table {
return &plugin.Table{
Name: "github_dependabot_alert",
Description: "",
List: &plugin.ListConfig{
KeyColumns: []*plugin.KeyColumn{
{
Name: "repository_full_name",
Require: plugin.Required,
},
{
Name: "state",
Require: plugin.Optional,
},
},
ShouldIgnoreError: isNotFoundError([]string{"404"}),
Hydrate: tableGitHubDependabotAlertList,
},
Get: &plugin.GetConfig{
KeyColumns: plugin.AllColumns([]string{"repository_full_name", "dependabot_number"}),
ShouldIgnoreError: isNotFoundError([]string{"404"}),
Hydrate: tableGitHubDependabotAlertGet,
},
Columns: []*plugin.Column{
{
Name: "repository_full_name",
Type: proto.ColumnType_STRING,
Transform: transform.FromQual("repository_full_name"),
Description: "The full name of the repository (login/repo-name).",
},
{
Name: "dependabot_number",
Type: proto.ColumnType_INT,
Description: "The security alert number.",
Transform: transform.FromField("Number"),
},
{
Name: "state",
Type: proto.ColumnType_STRING,
Description: "The state of the Dependabot alert.",
},
{
Name: "dependency_package_ecosystem",
Type: proto.ColumnType_STRING,
Description: "The package's language or package management ecosystem.",
Transform: transform.FromField("Dependency.Package.Ecosystem"),
},
{
Name: "dependency_package_name",
Type: proto.ColumnType_STRING,
Description: "The unique package name within its ecosystem.",
Transform: transform.FromField("Dependency.Package.Name"),
},
{
Name: "dependency_manifest_path",
Type: proto.ColumnType_STRING,
Description: "The unique package name within its ecosystem.",
Transform: transform.FromField("Dependency.ManifestPath"),
},
{
Name: "dependency_scope",
Type: proto.ColumnType_STRING,
Description: "The execution scope of the vulnerable dependency.",
Transform: transform.FromField("Dependency.Scope"),
},

{
Name: "url",
Type: proto.ColumnType_STRING,
Description: "The REST API URL of the alert resource.",
},
{
Name: "html_url",
Type: proto.ColumnType_STRING,
Description: "The GitHub URL of the alert resource.",
},
{
Name: "created_at",
Type: proto.ColumnType_TIMESTAMP,
Description: "The time that the alert was created.",
Transform: transform.FromField("CreatedAt").Transform(convertTimestamp),
},
{
Name: "updated_at",
Type: proto.ColumnType_TIMESTAMP,
Description: "The time that the alert was last updated.",
Transform: transform.FromField("UpdatedAt").Transform(convertTimestamp),
},
{
Name: "dismissed_at",
Type: proto.ColumnType_TIMESTAMP,
Description: "The time that the alert was dismissed.",
Transform: transform.FromField("DismissedAt").NullIfZero().Transform(convertTimestamp),
},
{
Name: "dismissed_reason",
Type: proto.ColumnType_STRING,
Description: "The reason that the alert was dismissed.",
},
{
Name: "dismissed_comment",
Type: proto.ColumnType_STRING,
Description: "An optional comment associated with the alert's dismissal.",
},
{
Name: "fixed_at",
Type: proto.ColumnType_TIMESTAMP,
Description: "The time that the alert was no longer detected and was considered fixed.",
Transform: transform.FromField("FixedAt").NullIfZero().Transform(convertTimestamp),
},
},
}
}

//// LIST FUNCTION

func tableGitHubDependabotAlertList(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) {
quals := d.KeyColumnQuals

fullName := quals["repository_full_name"].GetStringValue()
owner, repo := parseRepoFullName(fullName)

opt := &github.ListAlertsOptions{
ListCursorOptions: github.ListCursorOptions{First: 100},
}

if quals["state"] != nil {
state := quals["state"].GetStringValue()
opt.State = &state
}

type ListPageResponse struct {
alerts []*github.DependabotAlert
resp *github.Response
}

client := connect(ctx, d)

limit := d.QueryContext.Limit
if limit != nil {
if *limit < int64(opt.ListCursorOptions.First) {
opt.ListCursorOptions.First = int(*limit)
}
}

listPage := func(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) {
alerts, resp, err := client.Dependabot.ListRepoAlerts(ctx, owner, repo, opt)
return ListPageResponse{
alerts: alerts,
resp: resp,
}, err
}
for {
listPageResponse, err := retryHydrate(ctx, d, h, listPage)

if err != nil {
return nil, err
}

listResponse := listPageResponse.(ListPageResponse)
alerts := listResponse.alerts
resp := listResponse.resp

for _, i := range alerts {
d.StreamListItem(ctx, i)

// Context can be cancelled due to manual cancellation or the limit has been hit
if d.QueryStatus.RowsRemaining(ctx) == 0 {
return nil, nil
}
}

if resp.After == "" {
break
}

opt.ListCursorOptions.After = resp.After
}

return nil, nil
}

//// HYDRATE FUNCTIONS

func tableGitHubDependabotAlertGet(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) {
var owner, repo string
var alertNumber int

logger := plugin.Logger(ctx)
quals := d.KeyColumnQuals

alertNumber = int(d.KeyColumnQuals["dependabot_number"].GetInt64Value())
fullName := quals["repository_full_name"].GetStringValue()
owner, repo = parseRepoFullName(fullName)
logger.Trace("tableGitHubDependabotAlertGet", "owner", owner, "repo", repo, "alertNumber", alertNumber)

client := connect(ctx, d)

type GetResponse struct {
alert *github.DependabotAlert
resp *github.Response
}

getDetails := func(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) {
alert, resp, err := client.Dependabot.GetRepoAlert(ctx, owner, repo, alertNumber)
return GetResponse{
alert: alert,
resp: resp,
}, err
}

getResponse, err := retryHydrate(ctx, d, h, getDetails)
if err != nil {
return nil, err
}

getResp := getResponse.(GetResponse)
alert := getResp.alert

return alert, nil
}

0 comments on commit 9540e19

Please sign in to comment.