Skip to content

Commit

Permalink
feat: encrypted gh token
Browse files Browse the repository at this point in the history
Signed-off-by: Jad Chahed <[email protected]>
  • Loading branch information
Jad31 committed Aug 30, 2024
1 parent 1f765bd commit caac9f8
Show file tree
Hide file tree
Showing 9 changed files with 207 additions and 63 deletions.
14 changes: 12 additions & 2 deletions go/admin/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import (
"time"

"github.com/gin-contrib/cors"
"github.com/gin-contrib/sessions"
"github.com/gin-contrib/sessions/cookie"
"github.com/gin-gonic/gin"
"github.com/spf13/cobra"
"github.com/spf13/viper"
Expand All @@ -38,6 +40,7 @@ const (
flagMode = "admin-mode"
flagAdminAppId = "admin-gh-app-id"
flagAdminAppSecret = "admin-gh-app-secret"
flagGhAuth = "auth"
)

var workloads = []string{"OLTP", "OLTP-READONLY", "OLTP-SET", "TPCC", "TPCC_FK", "TPCC_FK_UNMANAGED", "TPCC_UNSHARDED"}

Check failure on line 46 in go/admin/admin.go

View workflow job for this annotation

GitHub Actions / Lint all go files

var `workloads` is unused (unused)
Expand All @@ -48,6 +51,7 @@ type Admin struct {

ghAppId string
ghAppSecret string
ghTokenSalt string

dbCfg *psdb.Config
dbClient *psdb.Client
Expand All @@ -60,11 +64,13 @@ func (a *Admin) AddToCommand(cmd *cobra.Command) {
cmd.Flags().Var(&a.Mode, flagMode, "Specify the mode on which the server will run")
cmd.Flags().StringVar(&a.ghAppId, flagAdminAppId, "", "The ID of the GitHub App")
cmd.Flags().StringVar(&a.ghAppSecret, flagAdminAppSecret, "", "The secret of the GitHub App")
cmd.Flags().StringVar(&a.ghTokenSalt, flagGhAuth, "", "The salt string to salt the GitHub Token")

_ = viper.BindPFlag(flagPort, cmd.Flags().Lookup(flagPort))
_ = viper.BindPFlag(flagMode, cmd.Flags().Lookup(flagMode))
_ = viper.BindPFlag(flagAdminAppId, cmd.Flags().Lookup(flagAdminAppId))
_ = viper.BindPFlag(flagAdminAppSecret, cmd.Flags().Lookup(flagAdminAppSecret))
_ = viper.BindPFlag(flagGhAuth, cmd.Flags().Lookup(flagGhAuth))

if a.dbCfg == nil {
a.dbCfg = &psdb.Config{}
Expand Down Expand Up @@ -113,15 +119,18 @@ func (a *Admin) Run() error {
a.Mode.SetGin()
a.router = gin.Default()

store := cookie.NewStore([]byte("secret"))
a.router.Use(sessions.Sessions("admin-session", store))

a.router.Static("/assets", filepath.Join(basepath, "assets"))

a.router.LoadHTMLGlob(filepath.Join(basepath, "templates/*"))

a.router.Use(cors.New(cors.Config{
AllowOrigins: []string{"*"},
AllowMethods: []string{"GET"},
AllowMethods: []string{"GET", "POST"},
AllowHeaders: []string{"Origin"},
ExposeHeaders: []string{"Content-Length"},
ExposeHeaders: []string{"Content-Length", "Content-Type"},
AllowCredentials: true,
MaxAge: 12 * time.Hour,
}))
Expand All @@ -130,6 +139,7 @@ func (a *Admin) Run() error {
a.router.GET("/admin", a.login)
a.router.GET("/admin/login", a.handleGitHubLogin)
a.router.GET("/admin/auth/callback", a.handleGitHubCallback)
a.router.POST("/admin/executions/add", a.handleExecutionsAdd)
a.router.GET("/admin/dashboard", a.authMiddleware(), a.dashboard)

return a.router.Run(":" + a.port)
Expand Down
87 changes: 79 additions & 8 deletions go/admin/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
package admin

import (
"bytes"
"context"
"encoding/json"
"net/http"
"strings"
"time"
Expand All @@ -39,26 +41,28 @@ var (
RedirectURL: "http://localhost:8081/admin/auth/callback",
}
oauthStateString = random.String(10) // A random string to protect against CSRF attacks
client *goGithub.Client

Check failure on line 44 in go/admin/api.go

View workflow job for this annotation

GitHub Actions / Lint all go files

var `client` is unused (unused)
)

const (
maintainerTeamGitHub = "maintainers"
arewefastyetTeamGitHub = "arewefastyet"
)

type ExecutionRequest struct {
Auth string `json:"auth"`
Source string `json:"source"`
SHA string `json:"sha"`
Workloads []string `json:"workloads"`
NumberOfExecutions string `json:"number_of_executions"`
}

func (a *Admin) login(c *gin.Context) {
a.render(c, gin.H{}, "login.html")
}

func (a *Admin) dashboard(c *gin.Context) {
user, err := c.Cookie("ghtoken")
if err != nil {
c.Abort()
return
}
a.render(c, gin.H{
"ghtoken": user,
}, "base.html")
a.render(c, gin.H{}, "base.html")
}

func (a *Admin) authMiddleware() gin.HandlerFunc {
Expand Down Expand Up @@ -153,3 +157,70 @@ func (a *Admin) checkUserOrgMembership(client *goGithub.Client, username, orgNam
}
return isMember, nil
}

func (a *Admin) handleExecutionsAdd(c *gin.Context) {
slog.Info("Adding execution")
token, err := c.Cookie("ghtoken")
source := c.PostForm("source")
sha := c.PostForm("sha")
workloads := c.PostFormArray("workloads")
numberOfExecutions := c.PostForm("numberOfExecutions")

if err != nil {
slog.Error("Failed to get token from cookie: ", err)
c.AbortWithStatus(http.StatusUnauthorized)
return
}

encryptedToken := server.Encrypt(token, a.ghTokenSalt)

requestPayload := ExecutionRequest{
Auth: encryptedToken,
Source: source,
SHA: sha,
Workloads: workloads,
NumberOfExecutions: numberOfExecutions,
}

jsonData, err := json.Marshal(requestPayload)

slog.Infof("Request payload: %s", jsonData)

if err != nil {
slog.Error("Failed to marshal request payload: ", err)
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to marshal request payload"})
return
}

serverAPIURL := "http://localhost:8080/api/executions/add"
// make a body with "admin-user": {encryptedToken}, "source": {source}, "sha": {sha}, "workloads": workloads, "numberOfExecutions": {numberOfExecutions}}

req, err := http.NewRequest("POST", serverAPIURL, bytes.NewBuffer(jsonData))

if err != nil {
slog.Error("Failed to create new HTTP request: ", err)
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create request to server API"})
return
}

req.Header.Set("Content-Type", "application/json")

// Execute the request
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
slog.Error("Failed to send request to server API: ", err)
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to send request to server API"})
return
}
defer resp.Body.Close()

// Handle the response from the server API
if resp.StatusCode != http.StatusOK {
slog.Error("Server API returned an error: ", resp.Status)
c.JSON(resp.StatusCode, gin.H{"error": "Failed to process request on server API"})
return
}

c.JSON(http.StatusOK, gin.H{"message": "Request forwarded to server API"})
}
2 changes: 1 addition & 1 deletion go/admin/templates/content.html
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
type="number" name="numberOfExecutions" value="1" min="1" max="10">
</div>

<button hx-post="http://localhost:8080/api/executions/add" hx-headers='{"admin-user": "{{.ghtoken}}"}'
<button hx-post="/admin/executions/add"
class="bg-orange-500 hover:bg-orange-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline"
type="submit">Add Execution</button>
</form>
Expand Down
36 changes: 0 additions & 36 deletions go/admin/templates/executions.html

This file was deleted.

3 changes: 2 additions & 1 deletion go/admin/templates/header.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
<div class="border-b-2 pb-4 mb-6">
<div class="border-b-2 pb-4 mb-6 w-full flex justify-between text-center flex-wrap">
<h2 class="text-2xl font-bold text-gray-700">Admin Dashboard</h2>
<a href="https://benchmark.vitess.io/" target="_blank" class="text-orange-500 align-middle">arewefastyet website</a>
</div>
6 changes: 4 additions & 2 deletions go/admin/templates/sidebar.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
<div id="sidebar">
<div class="mb-8">
<img src="/assets/logo.png" alt="Logo" class="mb-4" style="max-width: 100px;">
<h1 class="text-3xl font-bold text-orange-600">arewefastyet</h1>
<a href="/admin/dashboard" class="cursor-pointer">
<img src="/assets/logo.png" alt="Logo" class="mb-4" style="max-width: 100px;">
<h1 class="text-3xl font-bold text-orange-600">arewefastyet</h1>
</a>
</div>
<nav>
<ul>
Expand Down
41 changes: 30 additions & 11 deletions go/server/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
"github.com/vitessio/arewefastyet/go/tools/github"
"github.com/vitessio/arewefastyet/go/tools/macrobench"
"github.com/vitessio/arewefastyet/go/tools/microbench"
"github.com/vitessio/arewefastyet/go/tools/server"
"golang.org/x/exp/slices"
)

Expand Down Expand Up @@ -538,30 +539,48 @@ func (s *Server) getHistory(c *gin.Context) {
c.JSON(http.StatusOK, results)
}

type ExecutionRequest struct {
Auth string `json:"auth"`
Source string `json:"source"`
SHA string `json:"sha"`
Workloads []string `json:"workloads"`
NumberOfExecutions string `json:"number_of_executions"`
}

func (s *Server) addExecutions(c *gin.Context) {
source := c.PostForm("source")
sha := c.PostForm("sha")
workloads := c.PostFormArray("workloads")
numberOfExecutions := c.PostForm("numberOfExecutions")
slog.Info("Adding execution")

var req ExecutionRequest

if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"})
return
}

decryptedToken := server.Decrypt(req.Auth, s.ghTokenSalt)

slog.Info(decryptedToken)

if source == "" || sha == "" || len(workloads) == 0 || numberOfExecutions == "" {
slog.Infof("source: %s, sha: %s, workloads: %v, numberOfExecutions: %s, token: %s", req.Source, req.SHA, req.Workloads, req.NumberOfExecutions, decryptedToken)

if req.Source == "" || req.SHA == "" || len(req.Workloads) == 0 || req.NumberOfExecutions == "" {
c.JSON(http.StatusBadRequest, &ErrorAPI{Error: "missing argument"})
return
}

if len(workloads) == 1 && workloads[0] == "all" {
workloads = s.workloads
if len(req.Workloads) == 1 && req.Workloads[0] == "all" {
req.Workloads = s.workloads
}
execs, err := strconv.Atoi(numberOfExecutions)
execs, err := strconv.Atoi(req.NumberOfExecutions)
if err != nil {
c.JSON(http.StatusBadRequest, &ErrorAPI{Error: "numberOfExecutions must be an integer"})
return
}
newElements := make([]*executionQueueElement, 0, execs*len(workloads))
newElements := make([]*executionQueueElement, 0, execs*len(req.Workloads))

for _, workload := range workloads {
for _, workload := range req.Workloads {
for i := 0; i < execs; i++ {
elem := s.createSimpleExecutionQueueElement(s.benchmarkConfig[strings.ToLower(workload)], source, sha, workload, string(macrobench.Gen4Planner), false, 0, git.Version{})
elem := s.createSimpleExecutionQueueElement(s.benchmarkConfig[strings.ToLower(workload)], req.Source, req.SHA, workload, string(macrobench.Gen4Planner), false, 0, git.Version{})
elem.identifier.UUID = uuid.NewString()
newElements = append(newElements, elem)
}
Expand Down
8 changes: 6 additions & 2 deletions go/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ const (
flagFilterBySource = "web-source-filter"
flagExcludeFilterBySource = "web-source-exclude-filter"
flagRequestRunKey = "web-request-run-key"
flagGhAuth = "auth"

// keyMinimumVitessVersion is used to define on which minimum Vitess version a given
// benchmark should be run. Only the major version is counted. This key/value is located
Expand Down Expand Up @@ -95,7 +96,8 @@ type Server struct {
sourceFilter []string
excludeSourceFilter []string

ghApp *github.App
ghApp *github.App
ghTokenSalt string

requestRunKey string

Expand All @@ -119,6 +121,7 @@ func (s *Server) AddToCommand(cmd *cobra.Command) {
cmd.Flags().StringSliceVar(&s.sourceFilter, flagFilterBySource, nil, "List of execution source that should be run. By default, all sources are ran.")
cmd.Flags().StringSliceVar(&s.excludeSourceFilter, flagExcludeFilterBySource, nil, "List of execution source to not execute. By default, all sources are ran.")
cmd.Flags().StringVar(&s.requestRunKey, flagRequestRunKey, "", "Key to authenticate requests for custom benchmark runs.")
cmd.Flags().StringVar(&s.ghTokenSalt, flagGhAuth, "", "The salt string to salt the GitHub Token")

_ = viper.BindPFlag(flagPort, cmd.Flags().Lookup(flagPort))
_ = viper.BindPFlag(flagVitessPath, cmd.Flags().Lookup(flagVitessPath))
Expand All @@ -132,6 +135,7 @@ func (s *Server) AddToCommand(cmd *cobra.Command) {
_ = viper.BindPFlag(flagFilterBySource, cmd.Flags().Lookup(flagFilterBySource))
_ = viper.BindPFlag(flagExcludeFilterBySource, cmd.Flags().Lookup(flagExcludeFilterBySource))
_ = viper.BindPFlag(flagRequestRunKey, cmd.Flags().Lookup(flagRequestRunKey))
_ = viper.BindPFlag(flagGhAuth, cmd.Flags().Lookup(flagGhAuth))

s.slackConfig.AddToCommand(cmd)
if s.dbCfg == nil {
Expand Down Expand Up @@ -224,7 +228,7 @@ func (s *Server) Run() error {
s.router.Use(cors.New(cors.Config{
AllowOrigins: []string{"*"},
AllowMethods: []string{"GET", "POST"},
AllowHeaders: []string{"Origin", "hx-request", "hx-current-url", "admin-user"},
AllowHeaders: []string{"Origin", "hx-request", "hx-current-url", "Content-Type"},
ExposeHeaders: []string{"Content-Length"},
AllowCredentials: true,
MaxAge: 12 * time.Hour,
Expand Down
Loading

0 comments on commit caac9f8

Please sign in to comment.