From 3205a1913358f146e9f4fff9d735db7741a5040b Mon Sep 17 00:00:00 2001 From: Gal Birkman Date: Sun, 21 May 2023 16:29:51 +0300 Subject: [PATCH 1/3] feat: Added GitHub app authentication --- .gitignore | 2 +- README.md | 34 ++++++++++++++++++- config/config.go | 30 ++++++++++++++++- exporter/prometheus.go | 74 +++++++++++++++++++++++++++++++++++++++++- go.mod | 5 +++ go.sum | 17 ++++++++++ 6 files changed, 158 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 0b378f79..7bcc3741 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ .sequence - +*.pem .idea/ .vscode/ diff --git a/README.md b/README.md index 4d9391e6..cb915405 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,11 @@ This exporter is setup to take input from environment variables. All variables a the format "user1, user2". * `GITHUB_TOKEN` If supplied, enables the user to supply a github authentication token that allows the API to be queried more often. Optional, but recommended. * `GITHUB_TOKEN_FILE` If supplied _instead of_ `GITHUB_TOKEN`, enables the user to supply a path to a file containing a github authentication token that allows the API to be queried more often. Optional, but recommended. +* `GITHUB_APP` If true , authenticates ass GitHub app to the API. +* `GITHUB_APP_ID` The APP ID of the GitHub App. +* `GITHUB_APP_INSTALLATION_ID` The INSTALLATION ID of the GitHub App. +* `GITHUB_APP_KEY_PATH` The path to the github private key. +* `GITHUB_RATE_LIMIT` The RATE LIMIT that suppose to be for github app (default is 15,000). If the exporter sees the value is below this variable it generating new token for the app. * `API_URL` Github API URL, shouldn't need to change this. Defaults to `https://api.github.com` * `LISTEN_PORT` The port you wish to run the container on, the Dockerfile defaults this to `9171` * `METRICS_PATH` the metrics URL path you wish to use, defaults to `/metrics` @@ -27,10 +32,14 @@ Run manually from Docker Hub: docker run -d --restart=always -p 9171:9171 -e REPOS="infinityworks/ranch-eye, infinityworks/prom-conf" infinityworks/github-exporter ``` +Run manually from Docker Hub (With GitHub App): +``` +docker run -d --restart=always -p 9171:9171 --read-only -v ./key.pem:/key.pem -e GITHUB_APP=true -e GITHUB_APP_ID= -e GITHUB_APP_INSTALLATION_ID= -e GITHUB_APP_KEY_PATH=/key.pem +``` + Build a docker image: ``` docker build -t . -docker run -d --restart=always -p 9171:9171 -e REPOS="infinityworks/ranch-eye, infinityworks/prom-conf" ``` ## Docker compose @@ -47,6 +56,29 @@ github-exporter: environment: - REPOS= - GITHUB_TOKEN= +``` + +## Docker compose (GitHub App) + +``` +github-exporter-github-app: + tty: true + stdin_open: true + expose: + - 9171 + ports: + - 9171:9171 + build: . + environment: + - LOG_LEVEL=debug + - LISTEN_PORT=9171 + - GITHUB_APP=true + - GITHUB_APP_ID= + - GITHUB_APP_INSTALLATION_ID= + - GITHUB_APP_KEY_PATH=/key.pem + restart: unless-stopped + volumes: + - "./key.pem:/key.pem:ro" ``` diff --git a/config/config.go b/config/config.go index 278c5b0d..d6077fb4 100644 --- a/config/config.go +++ b/config/config.go @@ -1,11 +1,15 @@ package config import ( + "context" "io/ioutil" + "net/http" "net/url" "path" + "strconv" "strings" + "github.com/bradleyfalzon/ghinstallation" log "github.com/sirupsen/logrus" "os" @@ -22,6 +26,7 @@ type Config struct { users []string apiToken string targetURLs []string + gitHubApp bool } // Init populates the Config struct based on environmental runtime configuration @@ -39,6 +44,7 @@ func Init() Config { nil, "", nil, + false, } err := appConfig.SetAPIURL(cfg.GetEnv("API_URL", "https://api.github.com")) @@ -57,6 +63,15 @@ func Init() Config { if users != "" { appConfig.SetUsers(strings.Split(users, ", ")) } + + gitHubApp := os.Getenv("GITHUB_APP") + if gitHubApp == "true" { + gitHubAppKeyPath := os.Getenv("GITHUB_APP_KEY_PATH") + gitHubAppId, _ := strconv.ParseInt(os.Getenv("GITHUB_APP_ID"), 10, 64) + gitHubAppInstalaltionId, _ := strconv.ParseInt(os.Getenv("GITHUB_APP_INSTALLATION_ID"), 10, 64) + appConfig.SetAPITokenFromGitHubApp(gitHubAppId, gitHubAppInstalaltionId, gitHubAppKeyPath) + } + tokenEnv := os.Getenv("GITHUB_TOKEN") tokenFile := os.Getenv("GITHUB_TOKEN_FILE") if tokenEnv != "" { @@ -67,7 +82,6 @@ func Init() Config { log.Errorf("Error initialising Configuration, Error: %v", err) } } - return appConfig } @@ -126,6 +140,20 @@ func (c *Config) SetAPITokenFromFile(tokenFile string) error { return nil } +// SetAPITokenFromGitHubApp generating api token from github app configuration. +func (c *Config) SetAPITokenFromGitHubApp(gitHubAppId int64, gitHubAppInstalaltionId int64, gitHubAppKeyPath string) error { + itr, err := ghinstallation.NewKeyFromFile(http.DefaultTransport, gitHubAppId, gitHubAppInstalaltionId, gitHubAppKeyPath) + if err != nil { + return err + } + strToken, err := itr.Token(context.Background()) + if err != nil { + return err + } + c.SetAPIToken(strToken) + return nil +} + // Init populates the Config struct based on environmental runtime configuration // All URL's are added to the TargetURL's string array func (c *Config) setScrapeURLs() error { diff --git a/exporter/prometheus.go b/exporter/prometheus.go index 280c4f70..84d934cd 100644 --- a/exporter/prometheus.go +++ b/exporter/prometheus.go @@ -1,6 +1,15 @@ package exporter import ( + "context" + "errors" + "net/http" + "os" + "path" + "strconv" + "strings" + + "github.com/bradleyfalzon/ghinstallation" "github.com/prometheus/client_golang/prometheus" log "github.com/sirupsen/logrus" ) @@ -17,9 +26,20 @@ func (e *Exporter) Describe(ch chan<- *prometheus.Desc) { // Collect function, called on by Prometheus Client library // This function is called when a scrape is peformed on the /metrics page func (e *Exporter) Collect(ch chan<- prometheus.Metric) { - data := []*Datum{} var err error + + gitHubApp := os.Getenv("GITHUB_APP") + if strings.ToLower(gitHubApp) == "true" { + needReAuth, err := e.isTokenExpired() + if err != nil { + log.Errorf("Error checking token expiration status: %v", err) + return + } + if needReAuth { + e.reAuth() + } + } // Scrape the Data from Github if len(e.TargetURLs()) > 0 { data, err = e.gatherData() @@ -46,3 +66,55 @@ func (e *Exporter) Collect(ch chan<- prometheus.Metric) { log.Info("All Metrics successfully collected") } + +func (e *Exporter) isTokenExpired() (bool, error) { + u := *e.APIURL() + u.Path = path.Join(u.Path, "rate_limit") + + resp, err := getHTTPResponse(u.String(), e.APIToken()) + + if err != nil { + return false, err + } + defer resp.Body.Close() + // Triggers if rate-limiting isn't enabled on private Github Enterprise installations + if resp.StatusCode == 404 { + return false, errors.New("404 Error") + } + + limit, err := strconv.ParseFloat(resp.Header.Get("X-RateLimit-Limit"), 64) + + if err != nil { + return false, err + } + + defaultLimit := os.Getenv("GITHUB_RATE_LIMIT") + if len(defaultLimit) == 0 { + defaultLimit = "15000" + } + defaultLimitInt, err := strconv.ParseInt(defaultLimit, 10, 64) + if err != nil { + return false, err + } + if limit < float64(defaultLimitInt) { + return true, nil + } + return false, nil + +} + +func (e *Exporter) reAuth() error { + gitHubAppKeyPath := os.Getenv("GITHUB_APP_KEY_PATH") + gitHubAppId, _ := strconv.ParseInt(os.Getenv("GITHUB_APP_ID"), 10, 64) + gitHubAppInstalaltionId, _ := strconv.ParseInt(os.Getenv("GITHUB_APP_INSTALLATION_ID"), 10, 64) + itr, err := ghinstallation.NewKeyFromFile(http.DefaultTransport, gitHubAppId, gitHubAppInstalaltionId, gitHubAppKeyPath) + if err != nil { + return err + } + strToken, err := itr.Token(context.Background()) + if err != nil { + return err + } + e.Config.SetAPIToken(strToken) + return nil +} diff --git a/go.mod b/go.mod index 33087bc9..1d48d31b 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/infinityworks/github-exporter go 1.19 require ( + github.com/bradleyfalzon/ghinstallation v1.1.1 github.com/infinityworks/go-common v0.0.0-20170820165359-7f20a140fd37 github.com/prometheus/client_golang v1.14.0 github.com/sirupsen/logrus v1.9.0 @@ -14,7 +15,10 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect github.com/golang/protobuf v1.5.2 // indirect + github.com/google/go-github/v29 v29.0.2 // indirect + github.com/google/go-querystring v1.0.0 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect @@ -22,6 +26,7 @@ require ( github.com/prometheus/common v0.39.0 // indirect github.com/prometheus/procfs v0.9.0 // indirect github.com/stretchr/testify v1.8.0 // indirect + golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 // indirect golang.org/x/sys v0.4.0 // indirect google.golang.org/protobuf v1.28.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 9678b635..c65858bc 100644 --- a/go.sum +++ b/go.sum @@ -1,18 +1,28 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bradleyfalzon/ghinstallation v1.1.1 h1:pmBXkxgM1WeF8QYvDLT5kuQiHMcmf+X015GI0KM/E3I= +github.com/bradleyfalzon/ghinstallation v1.1.1/go.mod h1:vyCmHTciHx/uuyN82Zc3rXN3X2KTK8nUTCrTMwAhcug= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-github/v29 v29.0.2 h1:opYN6Wc7DOz7Ku3Oh4l7prmkOMwEcQxpFtxdU8N8Pts= +github.com/google/go-github/v29 v29.0.2/go.mod h1:CHKiKKPHJ0REzfwc14QMklvtHwCveD0PxlMjLlzAM5E= +github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/infinityworks/go-common v0.0.0-20170820165359-7f20a140fd37 h1:Lm6kyC3JBiJQvJrus66He0E4viqDc/m5BdiFNSkIFfU= github.com/infinityworks/go-common v0.0.0-20170820165359-7f20a140fd37/go.mod h1:+OaHNKQvQ9oOCr+DgkF95PkiDx20fLHpzMp8SmRPQTg= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -47,11 +57,18 @@ github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PK github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 h1:nrZ3ySNYwJbSpD6ce9duiP+QkD3JuLCcWkdaehUS/3Y= github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80/go.mod h1:iFyPdL66DjUD96XmzVL3ZntbzcflLnznH0fr99w5VqE= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= From f0537e19c026fa38d8dcaf2e921106275e5137c8 Mon Sep 17 00:00:00 2001 From: Gal Birkman Date: Mon, 8 Apr 2024 14:30:26 +0300 Subject: [PATCH 2/3] trivial: removed duplicated code and fixed CR comments --- config/config.go | 93 +++++++++++++++++++++++++++++++++++------- exporter/prometheus.go | 43 ++++--------------- 2 files changed, 87 insertions(+), 49 deletions(-) diff --git a/config/config.go b/config/config.go index 18d371f7..bb076943 100644 --- a/config/config.go +++ b/config/config.go @@ -2,7 +2,6 @@ package config import ( "context" - "io/ioutil" "net/http" "net/url" "path" @@ -20,13 +19,17 @@ import ( // Config struct holds all of the runtime confgiguration for the application type Config struct { *cfg.BaseConfig - apiUrl *url.URL - repositories []string - organisations []string - users []string - apiToken string - targetURLs []string - gitHubApp bool + apiUrl *url.URL + repositories []string + organisations []string + users []string + apiToken string + targetURLs []string + gitHubApp bool + gitHubAppKeyPath string + gitHubAppId int64 + gitHubAppInstallationId int64 + gitHubRateLimit float64 } // Init populates the Config struct based on environmental runtime configuration @@ -45,6 +48,10 @@ func Init() Config { "", nil, false, + "", + 0, + 0, + 15000, } err := appConfig.SetAPIURL(cfg.GetEnv("API_URL", "https://api.github.com")) @@ -64,12 +71,21 @@ func Init() Config { appConfig.SetUsers(strings.Split(users, ", ")) } - gitHubApp := os.Getenv("GITHUB_APP") + gitHubApp := strings.ToLower(os.Getenv("GITHUB_APP")) if gitHubApp == "true" { gitHubAppKeyPath := os.Getenv("GITHUB_APP_KEY_PATH") gitHubAppId, _ := strconv.ParseInt(os.Getenv("GITHUB_APP_ID"), 10, 64) gitHubAppInstalaltionId, _ := strconv.ParseInt(os.Getenv("GITHUB_APP_INSTALLATION_ID"), 10, 64) - appConfig.SetAPITokenFromGitHubApp(gitHubAppId, gitHubAppInstalaltionId, gitHubAppKeyPath) + gitHubRateLimit, _ := strconv.ParseFloat(cfg.GetEnv("GITHUB_RATE_LIMIT", "15000"), 64) + appConfig.SetGitHubApp(true) + appConfig.SetGitHubAppKeyPath(gitHubAppKeyPath) + appConfig.SetGitHubAppId(gitHubAppId) + appConfig.SetGitHubAppInstallationId(gitHubAppInstalaltionId) + appConfig.SetGitHubRateLimit(gitHubRateLimit) + err = appConfig.SetAPITokenFromGitHubApp() + if err != nil { + log.Errorf("Error initializing Configuration, Error: %v", err) + } } tokenEnv := os.Getenv("GITHUB_TOKEN") @@ -100,6 +116,31 @@ func (c *Config) APIToken() string { return c.apiToken } +// Returns the GitHub App atuhentication value +func (c *Config) GitHubApp() bool { + return c.gitHubApp +} + +// SetGitHubAppKeyPath accepts a string for GitHub app private key path +func (c *Config) GitHubAppKeyPath() string { + return c.gitHubAppKeyPath +} + +// SetGitHubAppId accepts a string for GitHub app id +func (c *Config) GitHubAppId() int64 { + return c.gitHubAppId +} + +// SetGitHubAppInstallationId accepts a string for GitHub app installation id +func (c *Config) GitHubAppInstallationId() int64 { + return c.gitHubAppInstallationId +} + +// SetGitHubAppRateLimit accepts a string for GitHub RateLimit +func (c *Config) GitHubRateLimit() float64 { + return c.gitHubRateLimit +} + // Sets the base API URL returning an error if the supplied string is not a valid URL func (c *Config) SetAPIURL(u string) error { ur, err := url.Parse(u) @@ -140,9 +181,34 @@ func (c *Config) SetAPITokenFromFile(tokenFile string) error { return nil } +// SetGitHubApp accepts a boolean for GitHub app authentication +func (c *Config) SetGitHubApp(githubApp bool) { + c.gitHubApp = githubApp +} + +// SetGitHubAppKeyPath accepts a string for GitHub app private key path +func (c *Config) SetGitHubAppKeyPath(gitHubAppKeyPath string) { + c.gitHubAppKeyPath = gitHubAppKeyPath +} + +// SetGitHubAppId accepts a string for GitHub app id +func (c *Config) SetGitHubAppId(gitHubAppId int64) { + c.gitHubAppId = gitHubAppId +} + +// SetGitHubAppInstallationId accepts a string for GitHub app installation id +func (c *Config) SetGitHubAppInstallationId(gitHubAppInstallationId int64) { + c.gitHubAppInstallationId = gitHubAppInstallationId +} + +// SetGitHubAppRateLimit accepts a string for GitHub RateLimit +func (c *Config) SetGitHubRateLimit(gitHubRateLimit float64) { + c.gitHubRateLimit = gitHubRateLimit +} + // SetAPITokenFromGitHubApp generating api token from github app configuration. -func (c *Config) SetAPITokenFromGitHubApp(gitHubAppId int64, gitHubAppInstalaltionId int64, gitHubAppKeyPath string) error { - itr, err := ghinstallation.NewKeyFromFile(http.DefaultTransport, gitHubAppId, gitHubAppInstalaltionId, gitHubAppKeyPath) +func (c *Config) SetAPITokenFromGitHubApp() error { + itr, err := ghinstallation.NewKeyFromFile(http.DefaultTransport, c.gitHubAppId, c.gitHubAppInstallationId, c.gitHubAppKeyPath) if err != nil { return err } @@ -181,8 +247,7 @@ func (c *Config) setScrapeURLs() error { } // Append github orginisations to the array - - + if len(c.organisations) > 0 { for _, x := range c.organisations { y := *c.apiUrl diff --git a/exporter/prometheus.go b/exporter/prometheus.go index 84d934cd..4023e1cc 100644 --- a/exporter/prometheus.go +++ b/exporter/prometheus.go @@ -1,15 +1,9 @@ package exporter import ( - "context" - "errors" - "net/http" - "os" "path" "strconv" - "strings" - "github.com/bradleyfalzon/ghinstallation" "github.com/prometheus/client_golang/prometheus" log "github.com/sirupsen/logrus" ) @@ -29,15 +23,17 @@ func (e *Exporter) Collect(ch chan<- prometheus.Metric) { data := []*Datum{} var err error - gitHubApp := os.Getenv("GITHUB_APP") - if strings.ToLower(gitHubApp) == "true" { + if e.Config.GitHubApp() { needReAuth, err := e.isTokenExpired() if err != nil { log.Errorf("Error checking token expiration status: %v", err) return } if needReAuth { - e.reAuth() + err = e.Config.SetAPITokenFromGitHubApp() + if err != nil { + log.Errorf("Error authenticating with GitHub app: %v", err) + } } } // Scrape the Data from Github @@ -79,7 +75,7 @@ func (e *Exporter) isTokenExpired() (bool, error) { defer resp.Body.Close() // Triggers if rate-limiting isn't enabled on private Github Enterprise installations if resp.StatusCode == 404 { - return false, errors.New("404 Error") + return false, nil } limit, err := strconv.ParseFloat(resp.Header.Get("X-RateLimit-Limit"), 64) @@ -88,33 +84,10 @@ func (e *Exporter) isTokenExpired() (bool, error) { return false, err } - defaultLimit := os.Getenv("GITHUB_RATE_LIMIT") - if len(defaultLimit) == 0 { - defaultLimit = "15000" - } - defaultLimitInt, err := strconv.ParseInt(defaultLimit, 10, 64) - if err != nil { - return false, err - } - if limit < float64(defaultLimitInt) { + defaultRateLimit := e.Config.GitHubRateLimit() + if limit < defaultRateLimit { return true, nil } return false, nil } - -func (e *Exporter) reAuth() error { - gitHubAppKeyPath := os.Getenv("GITHUB_APP_KEY_PATH") - gitHubAppId, _ := strconv.ParseInt(os.Getenv("GITHUB_APP_ID"), 10, 64) - gitHubAppInstalaltionId, _ := strconv.ParseInt(os.Getenv("GITHUB_APP_INSTALLATION_ID"), 10, 64) - itr, err := ghinstallation.NewKeyFromFile(http.DefaultTransport, gitHubAppId, gitHubAppInstalaltionId, gitHubAppKeyPath) - if err != nil { - return err - } - strToken, err := itr.Token(context.Background()) - if err != nil { - return err - } - e.Config.SetAPIToken(strToken) - return nil -} From 9878340f6cf9ea15013a8a9cf8cd02d0a9166862 Mon Sep 17 00:00:00 2001 From: Henry McConville Date: Tue, 23 Apr 2024 11:45:53 +0100 Subject: [PATCH 3/3] Update config/config.go --- config/config.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/config/config.go b/config/config.go index bb076943..9bb70dce 100644 --- a/config/config.go +++ b/config/config.go @@ -116,27 +116,27 @@ func (c *Config) APIToken() string { return c.apiToken } -// Returns the GitHub App atuhentication value +// Returns the GitHub App authentication value func (c *Config) GitHubApp() bool { return c.gitHubApp } -// SetGitHubAppKeyPath accepts a string for GitHub app private key path +// Returns the GitHub app private key path func (c *Config) GitHubAppKeyPath() string { return c.gitHubAppKeyPath } -// SetGitHubAppId accepts a string for GitHub app id +// Returns the GitHub app id func (c *Config) GitHubAppId() int64 { return c.gitHubAppId } -// SetGitHubAppInstallationId accepts a string for GitHub app installation id +// Returns the GitHub app installation id func (c *Config) GitHubAppInstallationId() int64 { return c.gitHubAppInstallationId } -// SetGitHubAppRateLimit accepts a string for GitHub RateLimit +// Returns the GitHub RateLimit func (c *Config) GitHubRateLimit() float64 { return c.gitHubRateLimit }