Skip to content

Commit caac9f8

Browse files
committed
feat: encrypted gh token
Signed-off-by: Jad Chahed <[email protected]>
1 parent 1f765bd commit caac9f8

File tree

9 files changed

+207
-63
lines changed

9 files changed

+207
-63
lines changed

go/admin/admin.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ import (
2626
"time"
2727

2828
"github.com/gin-contrib/cors"
29+
"github.com/gin-contrib/sessions"
30+
"github.com/gin-contrib/sessions/cookie"
2931
"github.com/gin-gonic/gin"
3032
"github.com/spf13/cobra"
3133
"github.com/spf13/viper"
@@ -38,6 +40,7 @@ const (
3840
flagMode = "admin-mode"
3941
flagAdminAppId = "admin-gh-app-id"
4042
flagAdminAppSecret = "admin-gh-app-secret"
43+
flagGhAuth = "auth"
4144
)
4245

4346
var workloads = []string{"OLTP", "OLTP-READONLY", "OLTP-SET", "TPCC", "TPCC_FK", "TPCC_FK_UNMANAGED", "TPCC_UNSHARDED"}
@@ -48,6 +51,7 @@ type Admin struct {
4851

4952
ghAppId string
5053
ghAppSecret string
54+
ghTokenSalt string
5155

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

6469
_ = viper.BindPFlag(flagPort, cmd.Flags().Lookup(flagPort))
6570
_ = viper.BindPFlag(flagMode, cmd.Flags().Lookup(flagMode))
6671
_ = viper.BindPFlag(flagAdminAppId, cmd.Flags().Lookup(flagAdminAppId))
6772
_ = viper.BindPFlag(flagAdminAppSecret, cmd.Flags().Lookup(flagAdminAppSecret))
73+
_ = viper.BindPFlag(flagGhAuth, cmd.Flags().Lookup(flagGhAuth))
6874

6975
if a.dbCfg == nil {
7076
a.dbCfg = &psdb.Config{}
@@ -113,15 +119,18 @@ func (a *Admin) Run() error {
113119
a.Mode.SetGin()
114120
a.router = gin.Default()
115121

122+
store := cookie.NewStore([]byte("secret"))
123+
a.router.Use(sessions.Sessions("admin-session", store))
124+
116125
a.router.Static("/assets", filepath.Join(basepath, "assets"))
117126

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

120129
a.router.Use(cors.New(cors.Config{
121130
AllowOrigins: []string{"*"},
122-
AllowMethods: []string{"GET"},
131+
AllowMethods: []string{"GET", "POST"},
123132
AllowHeaders: []string{"Origin"},
124-
ExposeHeaders: []string{"Content-Length"},
133+
ExposeHeaders: []string{"Content-Length", "Content-Type"},
125134
AllowCredentials: true,
126135
MaxAge: 12 * time.Hour,
127136
}))
@@ -130,6 +139,7 @@ func (a *Admin) Run() error {
130139
a.router.GET("/admin", a.login)
131140
a.router.GET("/admin/login", a.handleGitHubLogin)
132141
a.router.GET("/admin/auth/callback", a.handleGitHubCallback)
142+
a.router.POST("/admin/executions/add", a.handleExecutionsAdd)
133143
a.router.GET("/admin/dashboard", a.authMiddleware(), a.dashboard)
134144

135145
return a.router.Run(":" + a.port)

go/admin/api.go

Lines changed: 79 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919
package admin
2020

2121
import (
22+
"bytes"
2223
"context"
24+
"encoding/json"
2325
"net/http"
2426
"strings"
2527
"time"
@@ -39,26 +41,28 @@ var (
3941
RedirectURL: "http://localhost:8081/admin/auth/callback",
4042
}
4143
oauthStateString = random.String(10) // A random string to protect against CSRF attacks
44+
client *goGithub.Client
4245
)
4346

4447
const (
4548
maintainerTeamGitHub = "maintainers"
4649
arewefastyetTeamGitHub = "arewefastyet"
4750
)
4851

52+
type ExecutionRequest struct {
53+
Auth string `json:"auth"`
54+
Source string `json:"source"`
55+
SHA string `json:"sha"`
56+
Workloads []string `json:"workloads"`
57+
NumberOfExecutions string `json:"number_of_executions"`
58+
}
59+
4960
func (a *Admin) login(c *gin.Context) {
5061
a.render(c, gin.H{}, "login.html")
5162
}
5263

5364
func (a *Admin) dashboard(c *gin.Context) {
54-
user, err := c.Cookie("ghtoken")
55-
if err != nil {
56-
c.Abort()
57-
return
58-
}
59-
a.render(c, gin.H{
60-
"ghtoken": user,
61-
}, "base.html")
65+
a.render(c, gin.H{}, "base.html")
6266
}
6367

6468
func (a *Admin) authMiddleware() gin.HandlerFunc {
@@ -153,3 +157,70 @@ func (a *Admin) checkUserOrgMembership(client *goGithub.Client, username, orgNam
153157
}
154158
return isMember, nil
155159
}
160+
161+
func (a *Admin) handleExecutionsAdd(c *gin.Context) {
162+
slog.Info("Adding execution")
163+
token, err := c.Cookie("ghtoken")
164+
source := c.PostForm("source")
165+
sha := c.PostForm("sha")
166+
workloads := c.PostFormArray("workloads")
167+
numberOfExecutions := c.PostForm("numberOfExecutions")
168+
169+
if err != nil {
170+
slog.Error("Failed to get token from cookie: ", err)
171+
c.AbortWithStatus(http.StatusUnauthorized)
172+
return
173+
}
174+
175+
encryptedToken := server.Encrypt(token, a.ghTokenSalt)
176+
177+
requestPayload := ExecutionRequest{
178+
Auth: encryptedToken,
179+
Source: source,
180+
SHA: sha,
181+
Workloads: workloads,
182+
NumberOfExecutions: numberOfExecutions,
183+
}
184+
185+
jsonData, err := json.Marshal(requestPayload)
186+
187+
slog.Infof("Request payload: %s", jsonData)
188+
189+
if err != nil {
190+
slog.Error("Failed to marshal request payload: ", err)
191+
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to marshal request payload"})
192+
return
193+
}
194+
195+
serverAPIURL := "http://localhost:8080/api/executions/add"
196+
// make a body with "admin-user": {encryptedToken}, "source": {source}, "sha": {sha}, "workloads": workloads, "numberOfExecutions": {numberOfExecutions}}
197+
198+
req, err := http.NewRequest("POST", serverAPIURL, bytes.NewBuffer(jsonData))
199+
200+
if err != nil {
201+
slog.Error("Failed to create new HTTP request: ", err)
202+
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create request to server API"})
203+
return
204+
}
205+
206+
req.Header.Set("Content-Type", "application/json")
207+
208+
// Execute the request
209+
client := &http.Client{}
210+
resp, err := client.Do(req)
211+
if err != nil {
212+
slog.Error("Failed to send request to server API: ", err)
213+
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to send request to server API"})
214+
return
215+
}
216+
defer resp.Body.Close()
217+
218+
// Handle the response from the server API
219+
if resp.StatusCode != http.StatusOK {
220+
slog.Error("Server API returned an error: ", resp.Status)
221+
c.JSON(resp.StatusCode, gin.H{"error": "Failed to process request on server API"})
222+
return
223+
}
224+
225+
c.JSON(http.StatusOK, gin.H{"message": "Request forwarded to server API"})
226+
}

go/admin/templates/content.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
type="number" name="numberOfExecutions" value="1" min="1" max="10">
4343
</div>
4444

45-
<button hx-post="http://localhost:8080/api/executions/add" hx-headers='{"admin-user": "{{.ghtoken}}"}'
45+
<button hx-post="/admin/executions/add"
4646
class="bg-orange-500 hover:bg-orange-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline"
4747
type="submit">Add Execution</button>
4848
</form>

go/admin/templates/executions.html

Lines changed: 0 additions & 36 deletions
This file was deleted.

go/admin/templates/header.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1-
<div class="border-b-2 pb-4 mb-6">
1+
<div class="border-b-2 pb-4 mb-6 w-full flex justify-between text-center flex-wrap">
22
<h2 class="text-2xl font-bold text-gray-700">Admin Dashboard</h2>
3+
<a href="https://benchmark.vitess.io/" target="_blank" class="text-orange-500 align-middle">arewefastyet website</a>
34
</div>

go/admin/templates/sidebar.html

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
<div id="sidebar">
22
<div class="mb-8">
3-
<img src="/assets/logo.png" alt="Logo" class="mb-4" style="max-width: 100px;">
4-
<h1 class="text-3xl font-bold text-orange-600">arewefastyet</h1>
3+
<a href="/admin/dashboard" class="cursor-pointer">
4+
<img src="/assets/logo.png" alt="Logo" class="mb-4" style="max-width: 100px;">
5+
<h1 class="text-3xl font-bold text-orange-600">arewefastyet</h1>
6+
</a>
57
</div>
68
<nav>
79
<ul>

go/server/api.go

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import (
3333
"github.com/vitessio/arewefastyet/go/tools/github"
3434
"github.com/vitessio/arewefastyet/go/tools/macrobench"
3535
"github.com/vitessio/arewefastyet/go/tools/microbench"
36+
"github.com/vitessio/arewefastyet/go/tools/server"
3637
"golang.org/x/exp/slices"
3738
)
3839

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

542+
type ExecutionRequest struct {
543+
Auth string `json:"auth"`
544+
Source string `json:"source"`
545+
SHA string `json:"sha"`
546+
Workloads []string `json:"workloads"`
547+
NumberOfExecutions string `json:"number_of_executions"`
548+
}
549+
541550
func (s *Server) addExecutions(c *gin.Context) {
542-
source := c.PostForm("source")
543-
sha := c.PostForm("sha")
544-
workloads := c.PostFormArray("workloads")
545-
numberOfExecutions := c.PostForm("numberOfExecutions")
551+
slog.Info("Adding execution")
552+
553+
var req ExecutionRequest
554+
555+
if err := c.ShouldBindJSON(&req); err != nil {
556+
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"})
557+
return
558+
}
559+
560+
decryptedToken := server.Decrypt(req.Auth, s.ghTokenSalt)
561+
562+
slog.Info(decryptedToken)
546563

547-
if source == "" || sha == "" || len(workloads) == 0 || numberOfExecutions == "" {
564+
slog.Infof("source: %s, sha: %s, workloads: %v, numberOfExecutions: %s, token: %s", req.Source, req.SHA, req.Workloads, req.NumberOfExecutions, decryptedToken)
565+
566+
if req.Source == "" || req.SHA == "" || len(req.Workloads) == 0 || req.NumberOfExecutions == "" {
548567
c.JSON(http.StatusBadRequest, &ErrorAPI{Error: "missing argument"})
549568
return
550569
}
551570

552-
if len(workloads) == 1 && workloads[0] == "all" {
553-
workloads = s.workloads
571+
if len(req.Workloads) == 1 && req.Workloads[0] == "all" {
572+
req.Workloads = s.workloads
554573
}
555-
execs, err := strconv.Atoi(numberOfExecutions)
574+
execs, err := strconv.Atoi(req.NumberOfExecutions)
556575
if err != nil {
557576
c.JSON(http.StatusBadRequest, &ErrorAPI{Error: "numberOfExecutions must be an integer"})
558577
return
559578
}
560-
newElements := make([]*executionQueueElement, 0, execs*len(workloads))
579+
newElements := make([]*executionQueueElement, 0, execs*len(req.Workloads))
561580

562-
for _, workload := range workloads {
581+
for _, workload := range req.Workloads {
563582
for i := 0; i < execs; i++ {
564-
elem := s.createSimpleExecutionQueueElement(s.benchmarkConfig[strings.ToLower(workload)], source, sha, workload, string(macrobench.Gen4Planner), false, 0, git.Version{})
583+
elem := s.createSimpleExecutionQueueElement(s.benchmarkConfig[strings.ToLower(workload)], req.Source, req.SHA, workload, string(macrobench.Gen4Planner), false, 0, git.Version{})
565584
elem.identifier.UUID = uuid.NewString()
566585
newElements = append(newElements, elem)
567586
}

go/server/server.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ const (
5050
flagFilterBySource = "web-source-filter"
5151
flagExcludeFilterBySource = "web-source-exclude-filter"
5252
flagRequestRunKey = "web-request-run-key"
53+
flagGhAuth = "auth"
5354

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

98-
ghApp *github.App
99+
ghApp *github.App
100+
ghTokenSalt string
99101

100102
requestRunKey string
101103

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

123126
_ = viper.BindPFlag(flagPort, cmd.Flags().Lookup(flagPort))
124127
_ = viper.BindPFlag(flagVitessPath, cmd.Flags().Lookup(flagVitessPath))
@@ -132,6 +135,7 @@ func (s *Server) AddToCommand(cmd *cobra.Command) {
132135
_ = viper.BindPFlag(flagFilterBySource, cmd.Flags().Lookup(flagFilterBySource))
133136
_ = viper.BindPFlag(flagExcludeFilterBySource, cmd.Flags().Lookup(flagExcludeFilterBySource))
134137
_ = viper.BindPFlag(flagRequestRunKey, cmd.Flags().Lookup(flagRequestRunKey))
138+
_ = viper.BindPFlag(flagGhAuth, cmd.Flags().Lookup(flagGhAuth))
135139

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

0 commit comments

Comments
 (0)