github.com/mistwind/reviewdog@v0.0.0-20230322024206-9cfa11856d58/doghouse/appengine/main.go (about) 1 package main 2 3 import ( 4 "log" 5 "net/http" 6 "os" 7 "strconv" 8 9 "contrib.go.opencensus.io/exporter/stackdriver" 10 "contrib.go.opencensus.io/exporter/stackdriver/propagation" 11 "github.com/haya14busa/secretbox" 12 "github.com/justinas/nosurf" 13 "go.opencensus.io/plugin/ochttp" 14 "go.opencensus.io/trace" 15 16 "github.com/mistwind/reviewdog/doghouse/server/cookieman" 17 "github.com/mistwind/reviewdog/doghouse/server/storage" 18 ) 19 20 func mustCookieMan() *cookieman.CookieMan { 21 // Create secret key by following command. 22 // $ ruby -rsecurerandom -e 'puts SecureRandom.hex(32)' 23 cipher, err := secretbox.NewFromHexKey(mustGetenv("SECRETBOX_SECRET")) 24 if err != nil { 25 log.Fatalf("failed to create secretbox: %v", err) 26 } 27 c := cookieman.CookieOption{ 28 Cookie: http.Cookie{ 29 HttpOnly: true, 30 Secure: true, 31 Path: "/", 32 }, 33 } 34 return cookieman.New(cipher, c) 35 } 36 37 func mustGitHubAppsPrivateKey() []byte { 38 // Private keys https://github.com/settings/apps/reviewdog 39 githubAppsPrivateKey, err := os.ReadFile(mustGetenv("GITHUB_PRIVATE_KEY_FILE")) 40 if err != nil { 41 log.Fatalf("could not read private key: %s", err) 42 } 43 return githubAppsPrivateKey 44 } 45 46 func mustGetenv(name string) string { 47 s := os.Getenv(name) 48 if s == "" { 49 log.Fatalf("%s is not set", name) 50 } 51 return s 52 } 53 54 func mustIntEnv(name string) int { 55 s := os.Getenv(name) 56 if s == "" { 57 log.Fatalf("%s is not set", name) 58 } 59 i, err := strconv.Atoi(s) 60 if err != nil { 61 log.Fatal(err) 62 } 63 return i 64 } 65 66 func main() { 67 configureTrace() 68 initTemplates() 69 70 integrationID := mustIntEnv("GITHUB_INTEGRATION_ID") 71 ghPrivateKey := mustGitHubAppsPrivateKey() 72 73 ghInstStore := storage.GitHubInstallationDatastore{} 74 ghRepoTokenStore := storage.GitHubRepoTokenDatastore{} 75 76 ghHandler := NewGitHubHandler( 77 mustGetenv("GITHUB_CLIENT_ID"), 78 mustGetenv("GITHUB_CLIENT_SECRET"), 79 mustCookieMan(), 80 ghPrivateKey, 81 integrationID, 82 ) 83 84 ghChecker := githubChecker{ 85 privateKey: ghPrivateKey, 86 integrationID: integrationID, 87 ghInstStore: &ghInstStore, 88 ghRepoTokenStore: &ghRepoTokenStore, 89 tr: &ochttp.Transport{ 90 // Use Google Cloud propagation format. 91 Propagation: &propagation.HTTPFormat{}, 92 }, 93 } 94 95 ghWebhookHandler := githubWebhookHandler{ 96 secret: []byte(mustGetenv("GITHUB_WEBHOOK_SECRET")), 97 ghInstStore: &ghInstStore, 98 } 99 100 mu := http.NewServeMux() 101 102 // Register Admin handlers. 103 mu.HandleFunc("/_ah/warmup", warmupHandler) 104 105 handleFunc(mu, "/", handleTop) 106 handleFunc(mu, "/check", ghChecker.handleCheck) 107 handleFunc(mu, "/gh_/webhook", ghWebhookHandler.handleWebhook) 108 handleFunc(mu, "/gh_/auth/callback", ghHandler.HandleAuthCallback) 109 handleFunc(mu, "/gh_/logout", ghHandler.HandleLogout) 110 mu.Handle("/gh/", nosurf.New(ochttp.WithRouteTag(ghHandler.LogInHandler(http.HandlerFunc(ghHandler.HandleGitHubTop)), "/gh/"))) 111 112 http.Handle("/", mu) 113 log.Fatal(http.ListenAndServe(":"+os.Getenv("PORT"), &ochttp.Handler{ 114 Handler: mu, 115 Propagation: &propagation.HTTPFormat{}, 116 })) 117 } 118 119 func handleFunc(mu *http.ServeMux, pattern string, handler func(http.ResponseWriter, *http.Request)) { 120 mu.Handle(pattern, 121 ochttp.WithRouteTag(http.HandlerFunc(handler), pattern)) 122 } 123 124 func handleTop(w http.ResponseWriter, _ *http.Request) { 125 var data struct { 126 Title string 127 } 128 data.Title = "reviewdog" 129 topTmpl.ExecuteTemplate(w, "base", &data) 130 } 131 132 // Document: https://cloud.google.com/trace/docs/setup/go 133 func configureTrace() { 134 // Create and register a OpenCensus Stackdriver Trace exporter. 135 exporter, err := stackdriver.NewExporter(stackdriver.Options{ 136 ProjectID: os.Getenv("GOOGLE_CLOUD_PROJECT"), 137 }) 138 if err != nil { 139 log.Fatal(err) 140 } 141 trace.RegisterExporter(exporter) 142 trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()}) 143 }