|
1 | 1 | package github
|
2 | 2 |
|
3 | 3 | import (
|
| 4 | + "fmt" |
| 5 | + "net/http" |
| 6 | + "net/url" |
| 7 | + "strings" |
| 8 | + |
4 | 9 | gogit "github.com/go-git/go-git/v5"
|
5 | 10 | "github.com/google/go-github/v67/github"
|
| 11 | + "github.com/shurcooL/githubv4" |
| 12 | + |
6 | 13 | "github.com/trufflesecurity/trufflehog/v3/pkg/context"
|
| 14 | + "github.com/trufflesecurity/trufflehog/v3/pkg/log" |
| 15 | + "github.com/trufflesecurity/trufflehog/v3/pkg/pb/sourcespb" |
7 | 16 | )
|
8 | 17 |
|
9 |
| -const cloudEndpoint = "https://api.github.com" |
| 18 | +const ( |
| 19 | + cloudV3Endpoint = "https://api.github.com" |
| 20 | + cloudGraphqlEndpoint = "https://api.github.com/graphql" // https://docs.github.com/en/graphql/guides/forming-calls-with-graphql#the-graphql-endpoint |
| 21 | +) |
10 | 22 |
|
11 | 23 | // Connector abstracts over the authenticated ways to interact with GitHub: cloning and API operations.
|
12 | 24 | type Connector interface {
|
13 | 25 | // APIClient returns a configured GitHub client that can be used for GitHub API operations.
|
14 | 26 | APIClient() *github.Client
|
| 27 | + // GraphQLClient returns a client that can be used for GraphQL operations. |
| 28 | + GraphQLClient() *githubv4.Client |
15 | 29 | // Clone clones a repository using the configured authentication information.
|
16 | 30 | Clone(ctx context.Context, repoURL string, args ...string) (string, *gogit.Repository, error)
|
17 | 31 | }
|
| 32 | + |
| 33 | +func newConnector(ctx context.Context, source *Source) (Connector, error) { |
| 34 | + apiEndpoint := source.conn.Endpoint |
| 35 | + if apiEndpoint == "" || endsWithGithub.MatchString(apiEndpoint) { |
| 36 | + apiEndpoint = cloudV3Endpoint |
| 37 | + } |
| 38 | + |
| 39 | + switch cred := source.conn.GetCredential().(type) { |
| 40 | + case *sourcespb.GitHub_GithubApp: |
| 41 | + log.RedactGlobally(cred.GithubApp.GetPrivateKey()) |
| 42 | + return NewAppConnector(ctx, apiEndpoint, cred.GithubApp) |
| 43 | + case *sourcespb.GitHub_BasicAuth: |
| 44 | + log.RedactGlobally(cred.BasicAuth.GetPassword()) |
| 45 | + return NewBasicAuthConnector(ctx, apiEndpoint, cred.BasicAuth) |
| 46 | + case *sourcespb.GitHub_Token: |
| 47 | + log.RedactGlobally(cred.Token) |
| 48 | + return NewTokenConnector(ctx, apiEndpoint, cred.Token, func(c context.Context, err error) bool { |
| 49 | + return source.handleRateLimit(c, err) |
| 50 | + }) |
| 51 | + case *sourcespb.GitHub_Unauthenticated: |
| 52 | + return NewUnauthenticatedConnector(ctx, apiEndpoint) |
| 53 | + default: |
| 54 | + return nil, fmt.Errorf("unknown connection type %T", source.conn.GetCredential()) |
| 55 | + } |
| 56 | +} |
| 57 | + |
| 58 | +func createAPIClient(ctx context.Context, httpClient *http.Client, apiEndpoint string) (*github.Client, error) { |
| 59 | + getLogger(ctx).V(2).Info("Creating API client", "url", apiEndpoint) |
| 60 | + |
| 61 | + // If we're using public GitHub, make a regular client. |
| 62 | + // Otherwise, make an enterprise client. |
| 63 | + if strings.EqualFold(apiEndpoint, cloudV3Endpoint) { |
| 64 | + return github.NewClient(httpClient), nil |
| 65 | + } |
| 66 | + |
| 67 | + return github.NewClient(httpClient).WithEnterpriseURLs(apiEndpoint, apiEndpoint) |
| 68 | +} |
| 69 | + |
| 70 | +func createGraphqlClient(ctx context.Context, client *http.Client, apiEndpoint string) (*githubv4.Client, error) { |
| 71 | + var graphqlEndpoint string |
| 72 | + if apiEndpoint == cloudV3Endpoint { |
| 73 | + graphqlEndpoint = cloudGraphqlEndpoint |
| 74 | + } else { |
| 75 | + // Use the root endpoint for the host. |
| 76 | + // https://docs.github.com/en/[email protected]/graphql/guides/introduction-to-graphql |
| 77 | + parsedURL, err := url.Parse(apiEndpoint) |
| 78 | + if err != nil { |
| 79 | + return nil, fmt.Errorf("could not create GraphQL client: %w", err) |
| 80 | + } |
| 81 | + |
| 82 | + // GitHub Enterprise uses `/api/v3` for the base. (https://github.com/google/go-github/issues/958) |
| 83 | + // Swap it, and anything before `/api`, with GraphQL. |
| 84 | + before, _ := strings.CutSuffix(parsedURL.Path, "/api/v3") |
| 85 | + parsedURL.Path = before + "/api/graphql" |
| 86 | + graphqlEndpoint = parsedURL.String() |
| 87 | + } |
| 88 | + getLogger(ctx).V(2).Info("Creating GraphQL client", "url", graphqlEndpoint) |
| 89 | + |
| 90 | + return githubv4.NewEnterpriseClient(graphqlEndpoint, client), nil |
| 91 | +} |
0 commit comments