mirror of
https://github.com/sourcegraph/sourcegraph.git
synced 2026-02-06 18:11:48 +00:00
ci: get token from github app (#42674)
* create github-app token * use flags * gomod * return error * test gentoken * testing wip * add tests * addressing PR feedback * lint * go mod tidy * ineff * fix flags * Update enterprise/dev/ci/scripts/app-token/main_test.go Co-authored-by: Jean-Hadrien Chabran <jh@chabran.fr> * fix exit code Co-authored-by: Jean-Hadrien Chabran <jh@chabran.fr>
This commit is contained in:
parent
4345944f0a
commit
9a98849cb9
98
enterprise/dev/ci/scripts/app-token/main.go
Normal file
98
enterprise/dev/ci/scripts/app-token/main.go
Normal file
@ -0,0 +1,98 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/golang-jwt/jwt"
|
||||
"github.com/google/go-github/v47/github"
|
||||
"golang.org/x/oauth2"
|
||||
|
||||
"github.com/sourcegraph/sourcegraph/lib/errors"
|
||||
)
|
||||
|
||||
func main() {
|
||||
appID := flag.String("appid", os.Getenv("GITHUB_APP_ID"), "(required) github application id.")
|
||||
keyPath := flag.String("keypath", os.Getenv("KEY_PATH"), "(required) path to private key file for github app.")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
if len(*appID) == 0 || len(*keyPath) == 0 {
|
||||
flag.PrintDefaults()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
jwt, err := genJwtToken(*appID, *keyPath)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
ts := oauth2.StaticTokenSource(
|
||||
&oauth2.Token{AccessToken: jwt},
|
||||
)
|
||||
tc := oauth2.NewClient(ctx, ts)
|
||||
ghc := github.NewClient(tc)
|
||||
|
||||
appToken, err := getInstallAccessToken(ctx, ghc)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println(*appToken)
|
||||
}
|
||||
|
||||
func genJwtToken(appID string, keyPath string) (string, error) {
|
||||
rawPem, err := ioutil.ReadFile(keyPath)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "Failed to read key file.")
|
||||
}
|
||||
|
||||
privPem, _ := pem.Decode(rawPem)
|
||||
if privPem == nil {
|
||||
return "", errors.Wrap(nil, "failed to decode PEM block containing public key")
|
||||
}
|
||||
priv, err := x509.ParsePKCS1PrivateKey(privPem.Bytes)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "Failed to parse key.")
|
||||
}
|
||||
// Create new JWT token with 10 minute (max duration) expiry
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.MapClaims{
|
||||
"iat": time.Now().Unix() - 60,
|
||||
"exp": time.Now().Unix() + (10 * 60),
|
||||
"iss": appID,
|
||||
})
|
||||
|
||||
jwtString, err := token.SignedString(priv)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "Failed to create token.")
|
||||
}
|
||||
return jwtString, nil
|
||||
|
||||
}
|
||||
|
||||
func getInstallAccessToken(ctx context.Context, ghc *github.Client) (*string, error) {
|
||||
// Get organation installation ID
|
||||
orgInstallation, _, err := ghc.Apps.FindOrganizationInstallation(ctx, "sourcegraph")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
orgID := orgInstallation.ID
|
||||
|
||||
// Create new installation token with 60 minute duraction with default read repo contents permissions
|
||||
token, _, err := ghc.Apps.CreateInstallationToken(ctx, *orgID, &github.InstallationTokenOptions{
|
||||
Repositories: []string{"sourcegraph"},
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
return token.Token, nil
|
||||
}
|
||||
70
enterprise/dev/ci/scripts/app-token/main_test.go
Normal file
70
enterprise/dev/ci/scripts/app-token/main_test.go
Normal file
@ -0,0 +1,70 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/dnaeon/go-vcr/cassette"
|
||||
"github.com/google/go-github/v47/github"
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/oauth2"
|
||||
|
||||
"github.com/sourcegraph/sourcegraph/internal/httptestutil"
|
||||
)
|
||||
|
||||
var updateRecordings = flag.Bool("update-integration", false, "refresh integration test recordings")
|
||||
|
||||
func TestGenJwtToken(t *testing.T) {
|
||||
if os.Getenv("BUILDKITE") == "true" {
|
||||
t.Skip("Skipping testing in CI environment")
|
||||
} else {
|
||||
appID := os.Getenv("GITHUB_APP_ID")
|
||||
require.NotEmpty(t, appID, "GITHUB_APP_ID must be set.")
|
||||
keyPath := os.Getenv("KEY_PATH")
|
||||
require.NotEmpty(t, keyPath, "KEY_PATH must be set.")
|
||||
_, err := genJwtToken(appID, keyPath)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
func newTestGitHubClient(ctx context.Context, t *testing.T) (ghc *github.Client, stop func() error) {
|
||||
recording := filepath.Join("tests/testdata", strings.ReplaceAll(t.Name(), " ", "-"))
|
||||
recorder, err := httptestutil.NewRecorder(recording, *updateRecordings, func(i *cassette.Interaction) error {
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if *updateRecordings {
|
||||
appID := os.Getenv("GITHUB_APP_ID")
|
||||
require.NotEmpty(t, appID, "GITHUB_APP_ID must be set.")
|
||||
keyPath := os.Getenv("KEY_PATH")
|
||||
require.NotEmpty(t, keyPath, "KEY_PATH must be set.")
|
||||
jwt, err := genJwtToken(appID, keyPath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
httpClient := oauth2.NewClient(ctx, oauth2.StaticTokenSource(
|
||||
&oauth2.Token{AccessToken: jwt},
|
||||
))
|
||||
recorder.SetTransport(httpClient.Transport)
|
||||
}
|
||||
}
|
||||
return github.NewClient(&http.Client{Transport: recorder}), recorder.Stop
|
||||
|
||||
}
|
||||
|
||||
func TestGetInstallAccessToken(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
ghc, stop := newTestGitHubClient(ctx, t)
|
||||
defer stop()
|
||||
|
||||
_, err := getInstallAccessToken(ctx, ghc)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
113
enterprise/dev/ci/scripts/app-token/tests/testdata/TestGetInstallAccessToken.yaml
vendored
Normal file
113
enterprise/dev/ci/scripts/app-token/tests/testdata/TestGetInstallAccessToken.yaml
vendored
Normal file
@ -0,0 +1,113 @@
|
||||
---
|
||||
version: 1
|
||||
interactions:
|
||||
- request:
|
||||
body: ""
|
||||
form: {}
|
||||
headers:
|
||||
Accept:
|
||||
- application/vnd.github.v3+json
|
||||
User-Agent:
|
||||
- go-github/v47.0.0
|
||||
url: https://api.github.com/orgs/sourcegraph/installation
|
||||
method: GET
|
||||
response:
|
||||
body: '{"id":30579796,"account":{"login":"sourcegraph","id":3979584,"node_id":"MDEyOk9yZ2FuaXphdGlvbjM5Nzk1ODQ=","avatar_url":"https://avatars.githubusercontent.com/u/3979584?v=4","gravatar_id":"","url":"https://api.github.com/users/sourcegraph","html_url":"https://github.com/sourcegraph","followers_url":"https://api.github.com/users/sourcegraph/followers","following_url":"https://api.github.com/users/sourcegraph/following{/other_user}","gists_url":"https://api.github.com/users/sourcegraph/gists{/gist_id}","starred_url":"https://api.github.com/users/sourcegraph/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sourcegraph/subscriptions","organizations_url":"https://api.github.com/users/sourcegraph/orgs","repos_url":"https://api.github.com/users/sourcegraph/repos","events_url":"https://api.github.com/users/sourcegraph/events{/privacy}","received_events_url":"https://api.github.com/users/sourcegraph/received_events","type":"Organization","site_admin":false},"repository_selection":"selected","access_tokens_url":"https://api.github.com/app/installations/30579796/access_tokens","repositories_url":"https://api.github.com/installation/repositories","html_url":"https://github.com/organizations/sourcegraph/settings/installations/30579796","app_id":244693,"app_slug":"buildkite-token-gen","target_id":3979584,"target_type":"Organization","permissions":{"contents":"read","metadata":"read"},"events":[],"created_at":"2022-10-25T12:35:08.000Z","updated_at":"2022-10-25T12:35:09.000Z","single_file_name":null,"has_multiple_single_files":false,"single_file_paths":[],"suspended_by":null,"suspended_at":null}'
|
||||
headers:
|
||||
Access-Control-Allow-Origin:
|
||||
- '*'
|
||||
Access-Control-Expose-Headers:
|
||||
- ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining,
|
||||
X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes,
|
||||
X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO,
|
||||
X-GitHub-Request-Id, Deprecation, Sunset
|
||||
Cache-Control:
|
||||
- public, max-age=60, s-maxage=60
|
||||
Content-Security-Policy:
|
||||
- default-src 'none'
|
||||
Content-Type:
|
||||
- application/json; charset=utf-8
|
||||
Date:
|
||||
- Tue, 25 Oct 2022 14:27:36 GMT
|
||||
Etag:
|
||||
- W/"5fd5963d4e6164d8a0976397a1e24af2454fea5d3f31a9c100f8d6d04a8219ee"
|
||||
Referrer-Policy:
|
||||
- origin-when-cross-origin, strict-origin-when-cross-origin
|
||||
Server:
|
||||
- GitHub.com
|
||||
Strict-Transport-Security:
|
||||
- max-age=31536000; includeSubdomains; preload
|
||||
Vary:
|
||||
- Accept
|
||||
- Accept-Encoding, Accept, X-Requested-With
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Frame-Options:
|
||||
- deny
|
||||
X-Github-Media-Type:
|
||||
- github.v3; format=json
|
||||
X-Github-Request-Id:
|
||||
- E647:08F0:C5A40A:194F1A7:6357F258
|
||||
X-Xss-Protection:
|
||||
- "0"
|
||||
status: 200 OK
|
||||
code: 200
|
||||
duration: ""
|
||||
- request:
|
||||
body: |
|
||||
{"repositories":["sourcegraph"]}
|
||||
form: {}
|
||||
headers:
|
||||
Accept:
|
||||
- application/vnd.github.v3+json
|
||||
Content-Type:
|
||||
- application/json
|
||||
User-Agent:
|
||||
- go-github/v47.0.0
|
||||
url: https://api.github.com/app/installations/30579796/access_tokens
|
||||
method: POST
|
||||
response:
|
||||
body: '{"token":"dummy","expires_at":"2022-10-25T15:27:36Z","permissions":{"contents":"read","metadata":"read"},"repository_selection":"selected","repositories":[{"id":41288708,"node_id":"MDEwOlJlcG9zaXRvcnk0MTI4ODcwOA==","name":"sourcegraph","full_name":"sourcegraph/sourcegraph","private":false,"owner":{"login":"sourcegraph","id":3979584,"node_id":"MDEyOk9yZ2FuaXphdGlvbjM5Nzk1ODQ=","avatar_url":"https://avatars.githubusercontent.com/u/3979584?v=4","gravatar_id":"","url":"https://api.github.com/users/sourcegraph","html_url":"https://github.com/sourcegraph","followers_url":"https://api.github.com/users/sourcegraph/followers","following_url":"https://api.github.com/users/sourcegraph/following{/other_user}","gists_url":"https://api.github.com/users/sourcegraph/gists{/gist_id}","starred_url":"https://api.github.com/users/sourcegraph/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sourcegraph/subscriptions","organizations_url":"https://api.github.com/users/sourcegraph/orgs","repos_url":"https://api.github.com/users/sourcegraph/repos","events_url":"https://api.github.com/users/sourcegraph/events{/privacy}","received_events_url":"https://api.github.com/users/sourcegraph/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/sourcegraph/sourcegraph","description":"Universal
|
||||
code search (self-hosted)","fork":false,"url":"https://api.github.com/repos/sourcegraph/sourcegraph","forks_url":"https://api.github.com/repos/sourcegraph/sourcegraph/forks","keys_url":"https://api.github.com/repos/sourcegraph/sourcegraph/keys{/key_id}","collaborators_url":"https://api.github.com/repos/sourcegraph/sourcegraph/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/sourcegraph/sourcegraph/teams","hooks_url":"https://api.github.com/repos/sourcegraph/sourcegraph/hooks","issue_events_url":"https://api.github.com/repos/sourcegraph/sourcegraph/issues/events{/number}","events_url":"https://api.github.com/repos/sourcegraph/sourcegraph/events","assignees_url":"https://api.github.com/repos/sourcegraph/sourcegraph/assignees{/user}","branches_url":"https://api.github.com/repos/sourcegraph/sourcegraph/branches{/branch}","tags_url":"https://api.github.com/repos/sourcegraph/sourcegraph/tags","blobs_url":"https://api.github.com/repos/sourcegraph/sourcegraph/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/sourcegraph/sourcegraph/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/sourcegraph/sourcegraph/git/refs{/sha}","trees_url":"https://api.github.com/repos/sourcegraph/sourcegraph/git/trees{/sha}","statuses_url":"https://api.github.com/repos/sourcegraph/sourcegraph/statuses/{sha}","languages_url":"https://api.github.com/repos/sourcegraph/sourcegraph/languages","stargazers_url":"https://api.github.com/repos/sourcegraph/sourcegraph/stargazers","contributors_url":"https://api.github.com/repos/sourcegraph/sourcegraph/contributors","subscribers_url":"https://api.github.com/repos/sourcegraph/sourcegraph/subscribers","subscription_url":"https://api.github.com/repos/sourcegraph/sourcegraph/subscription","commits_url":"https://api.github.com/repos/sourcegraph/sourcegraph/commits{/sha}","git_commits_url":"https://api.github.com/repos/sourcegraph/sourcegraph/git/commits{/sha}","comments_url":"https://api.github.com/repos/sourcegraph/sourcegraph/comments{/number}","issue_comment_url":"https://api.github.com/repos/sourcegraph/sourcegraph/issues/comments{/number}","contents_url":"https://api.github.com/repos/sourcegraph/sourcegraph/contents/{+path}","compare_url":"https://api.github.com/repos/sourcegraph/sourcegraph/compare/{base}...{head}","merges_url":"https://api.github.com/repos/sourcegraph/sourcegraph/merges","archive_url":"https://api.github.com/repos/sourcegraph/sourcegraph/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/sourcegraph/sourcegraph/downloads","issues_url":"https://api.github.com/repos/sourcegraph/sourcegraph/issues{/number}","pulls_url":"https://api.github.com/repos/sourcegraph/sourcegraph/pulls{/number}","milestones_url":"https://api.github.com/repos/sourcegraph/sourcegraph/milestones{/number}","notifications_url":"https://api.github.com/repos/sourcegraph/sourcegraph/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/sourcegraph/sourcegraph/labels{/name}","releases_url":"https://api.github.com/repos/sourcegraph/sourcegraph/releases{/id}","deployments_url":"https://api.github.com/repos/sourcegraph/sourcegraph/deployments","created_at":"2015-08-24T07:27:28Z","updated_at":"2022-10-25T08:43:48Z","pushed_at":"2022-10-25T14:27:19Z","git_url":"git://github.com/sourcegraph/sourcegraph.git","ssh_url":"git@github.com:sourcegraph/sourcegraph.git","clone_url":"https://github.com/sourcegraph/sourcegraph.git","svn_url":"https://github.com/sourcegraph/sourcegraph","homepage":"https://sourcegraph.com","size":797242,"stargazers_count":7045,"watchers_count":7045,"language":"Go","has_issues":true,"has_projects":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":850,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":4673,"license":{"key":"other","name":"Other","spdx_id":"NOASSERTION","url":null,"node_id":"MDc6TGljZW5zZTA="},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"topics":["code-intelligence","code-search","lsif-enabled","open-source","repo-type-main","sourcegraph"],"visibility":"public","forks":850,"open_issues":4673,"watchers":7045,"default_branch":"main"}]}'
|
||||
headers:
|
||||
Access-Control-Allow-Origin:
|
||||
- '*'
|
||||
Access-Control-Expose-Headers:
|
||||
- ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining,
|
||||
X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes,
|
||||
X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO,
|
||||
X-GitHub-Request-Id, Deprecation, Sunset
|
||||
Cache-Control:
|
||||
- public, max-age=60, s-maxage=60
|
||||
Content-Length:
|
||||
- "5577"
|
||||
Content-Security-Policy:
|
||||
- default-src 'none'
|
||||
Content-Type:
|
||||
- application/json; charset=utf-8
|
||||
Date:
|
||||
- Tue, 25 Oct 2022 14:27:36 GMT
|
||||
Etag:
|
||||
- '"75eee91f9a00496ee85b18131e18dbcb9e867504cbb64204b4dff8107989190f"'
|
||||
Referrer-Policy:
|
||||
- origin-when-cross-origin, strict-origin-when-cross-origin
|
||||
Server:
|
||||
- GitHub.com
|
||||
Strict-Transport-Security:
|
||||
- max-age=31536000; includeSubdomains; preload
|
||||
Vary:
|
||||
- Accept
|
||||
- Accept-Encoding, Accept, X-Requested-With
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Frame-Options:
|
||||
- deny
|
||||
X-Github-Media-Type:
|
||||
- github.v3; format=json
|
||||
X-Github-Request-Id:
|
||||
- E647:08F0:C5A443:194F21D:6357F258
|
||||
X-Xss-Protection:
|
||||
- "0"
|
||||
status: 201 Created
|
||||
code: 201
|
||||
duration: ""
|
||||
2
go.mod
2
go.mod
@ -219,6 +219,8 @@ require (
|
||||
github.com/coreos/go-iptables v0.6.0
|
||||
github.com/dcadenas/pagerank v0.0.0-20171013173705-af922e3ceea8
|
||||
github.com/frankban/quicktest v1.14.3
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||
github.com/google/go-github/v47 v47.1.0
|
||||
github.com/hashicorp/hcl v1.0.0
|
||||
github.com/opsgenie/opsgenie-go-sdk-v2 v1.2.13
|
||||
github.com/prometheus/prometheus v0.37.1
|
||||
|
||||
3
go.sum
3
go.sum
@ -1035,6 +1035,7 @@ github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXP
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM=
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||
github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
||||
github.com/golang-jwt/jwt/v4 v4.1.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
||||
@ -1154,6 +1155,8 @@ github.com/google/go-github/v41 v41.0.0 h1:HseJrM2JFf2vfiZJ8anY2hqBjdfY1Vlj/K27u
|
||||
github.com/google/go-github/v41 v41.0.0/go.mod h1:XgmCA5H323A9rtgExdTcnDkcqp6S30AVACCBDOonIxg=
|
||||
github.com/google/go-github/v43 v43.0.0 h1:y+GL7LIsAIF2NZlJ46ZoC/D1W1ivZasT0lnWHMYPZ+U=
|
||||
github.com/google/go-github/v43 v43.0.0/go.mod h1:ZkTvvmCXBvsfPpTHXnH/d2hP9Y0cTbvN9kr5xqyXOIc=
|
||||
github.com/google/go-github/v47 v47.1.0 h1:Cacm/WxQBOa9lF0FT0EMjZ2BWMetQ1TQfyurn4yF1z8=
|
||||
github.com/google/go-github/v47 v47.1.0/go.mod h1:VPZBXNbFSJGjyjFRUKo9vZGawTajnWzC/YjGw/oFKi0=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
||||
|
||||
Loading…
Reference in New Issue
Block a user