Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions github/repo_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package github
import (
"context"
"fmt"
"os"
"slices"

"github.com/shurcooL/githubv4"
Expand Down Expand Up @@ -407,6 +408,10 @@ func extractRepoFromHydrateItem(h *plugin.HydrateData) (models.Repository, error
}

func appendRepoColumnIncludes(m *map[string]interface{}, cols []string) {
appendRepoColumnIncludesWithQueryData(m, cols, nil)
}

func appendRepoColumnIncludesWithQueryData(m *map[string]interface{}, cols []string, d *plugin.QueryData) {
optionals := map[string]string{
"allow_update_branch": "includeAllowUpdateBranch",
"archived_at": "includeArchivedAt",
Expand Down Expand Up @@ -480,6 +485,18 @@ func appendRepoColumnIncludes(m *map[string]interface{}, cols []string) {
for key, value := range optionals {
(*m)[value] = githubv4.Boolean(slices.Contains(cols, key))
}

// Handle interaction_ability for Fine-Grained PATs in github_my_repository table
// With Fine-grained access token we are getting field error even though we have proper access.
// https://spec.graphql.org/October2021/#sec-Errors.Field-errors
// https://spec.graphql.org/October2021/#sec-Handling-Field-Errors
if d != nil && slices.Contains(cols, "interaction_ability") {
githubConfig := GetConfig(d.Connection)
token := os.Getenv("GITHUB_TOKEN")
if isGitHubPAT(token) || (githubConfig.Token != nil && isGitHubPAT(*githubConfig.Token)) {
(*m)["includeUserInteractionAbility"] = githubv4.Boolean(false)
}
}
}

func repoHydrateAllowUpdateBranch(_ context.Context, _ *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) {
Expand Down
67 changes: 65 additions & 2 deletions github/table_github_my_repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,43 @@ package github

import (
"context"
"os"
"strings"

"github.com/google/go-github/v55/github"
"github.com/shurcooL/githubv4"
"github.com/turbot/steampipe-plugin-github/github/models"
"github.com/turbot/steampipe-plugin-sdk/v5/grpc/proto"
"github.com/turbot/steampipe-plugin-sdk/v5/plugin"
"github.com/turbot/steampipe-plugin-sdk/v5/plugin/transform"
)

func tableGitHubMyRepository() *plugin.Table {
// Get shared columns and override hooks column with Fine-Grained PAT handling
columns := sharedRepositoryColumns()

// Override hooks column to use the Fine-Grained PAT-aware hydrate function
for i, col := range columns {
if col.Name == "hooks" {
columns[i] = &plugin.Column{
Name: "hooks",
Type: proto.ColumnType_JSON,
Description: "The API Hooks URL.",
Hydrate: hydrateMyRepositoryHooksFromV3,
Transform: transform.FromValue(),
}
break
}
}

return &plugin.Table{
Name: "github_my_repository",
Description: "GitHub Repositories that you are associated with. GitHub Repositories contain all of your project's files and each file's revision history.",
List: &plugin.ListConfig{
Hydrate: tableGitHubMyRepositoryList,
ShouldIgnoreError: isNotFoundError([]string{"404"}),
},
Columns: commonColumns(sharedRepositoryColumns()),
Columns: commonColumns(columns),
}
}

Expand All @@ -39,7 +62,7 @@ func tableGitHubMyRepositoryList(ctx context.Context, d *plugin.QueryData, h *pl
"pageSize": githubv4.Int(pageSize),
"cursor": (*githubv4.String)(nil),
}
appendRepoColumnIncludes(&variables, d.QueryContext.Columns)
appendRepoColumnIncludesWithQueryData(&variables, d.QueryContext.Columns, d)

for {
err := client.Query(ctx, &query, variables)
Expand All @@ -66,3 +89,43 @@ func tableGitHubMyRepositoryList(ctx context.Context, d *plugin.QueryData, h *pl

return nil, nil
}

// hydrateMyRepositoryHooksFromV3 is a version of hydrateRepositoryHooksFromV3
// that skips hooks for Fine-Grained PATs (only for github_my_repository table)
func hydrateMyRepositoryHooksFromV3(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) {
// Skip hooks for Fine-Grained PATs to avoid field errors
// With Fine-grained access token we are getting field error even though we have proper access.
// https://spec.graphql.org/October2021/#sec-Errors.Field-errors
// https://spec.graphql.org/October2021/#sec-Handling-Field-Errors
githubConfig := GetConfig(d.Connection)
token := os.Getenv("GITHUB_TOKEN")
if isGitHubPAT(token) || (githubConfig.Token != nil && isGitHubPAT(*githubConfig.Token)) {
return nil, nil
}

repo, err := extractRepoFromHydrateItem(h)
if err != nil {
return nil, err
}
owner := repo.Owner.Login
repoName := repo.Name

client := connect(ctx, d)
var repositoryHooks []*github.Hook
opt := &github.ListOptions{PerPage: 100}

for {
hooks, resp, err := client.Repositories.ListHooks(ctx, owner, repoName, opt)
if err != nil && strings.Contains(err.Error(), "Not Found") {
return nil, nil
} else if err != nil {
return nil, err
}
repositoryHooks = append(repositoryHooks, hooks...)
if resp.NextPage == 0 {
break
}
opt.Page = resp.NextPage
}
return repositoryHooks, nil
}
Loading