Skip to content

Commit d1dc963

Browse files
committed
Add customer support
Signed-off-by: Alex Ellis <[email protected]>
1 parent 56d0e9f commit d1dc963

File tree

11 files changed

+574
-17
lines changed

11 files changed

+574
-17
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,6 @@ derek
1818
auth/*.pem
1919

2020
*.pem
21+
template
22+
build
23+
secrets.yml

Dockerfile

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM golang:1.7.5 as build
1+
FROM golang:1.9.2-alpine as build
22

33
RUN mkdir -p /go/src/github.com/alexellis/derek
44
WORKDIR /go/src/github.com/alexellis/derek
@@ -9,7 +9,7 @@ FROM alpine:3.5
99

1010
RUN apk --no-cache add curl ca-certificates \
1111
&& echo "Pulling watchdog binary from Github." \
12-
&& curl -sSL https://github.com/alexellis/faas/releases/download/0.6.5/fwatchdog > /usr/bin/fwatchdog \
12+
&& curl -sSL https://github.com/alexellis/faas/releases/download/0.6.9/fwatchdog > /usr/bin/fwatchdog \
1313
&& chmod +x /usr/bin/fwatchdog \
1414
&& apk del curl --no-cache
1515

@@ -22,6 +22,7 @@ COPY derek.pem .
2222
ENV cgi_headers="true"
2323
ENV validate_hmac="true"
2424
ENV fprocess="./derek"
25+
ENV validate_customers="true"
2526

2627
EXPOSE 8080
2728
CMD ["fwatchdog"]

auth/client_factory.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@ type JwtAuth struct {
1919
}
2020

2121
// MakeAccessTokenForInstallation makes an access token for an installation / private key
22-
func MakeAccessTokenForInstallation(appID, installation, privateKeyPath string) (string, error) {
22+
func MakeAccessTokenForInstallation(appID string, installation int, privateKeyPath string) (string, error) {
2323
signed, err := GetSignedJwtToken(appID, privateKeyPath)
2424

2525
if err == nil {
2626
c := http.Client{}
27-
req, _ := http.NewRequest(http.MethodPost, fmt.Sprintf("https://api.github.com/installations/%s/access_tokens", installation), nil)
27+
req, _ := http.NewRequest(http.MethodPost, fmt.Sprintf("https://api.github.com/installations/%d/access_tokens", installation), nil)
2828

2929
req.Header.Add("Authorization", "Bearer "+signed)
3030
req.Header.Add("Accept", "application/vnd.github.machine-man-preview+json")

auth/customers.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package auth
2+
3+
import (
4+
"io/ioutil"
5+
"net/http"
6+
"os"
7+
"strings"
8+
9+
"github.com/alexellis/derek/types"
10+
)
11+
12+
func IsCustomer(repo types.Repository) (bool, error) {
13+
validate := os.Getenv("validate_customers")
14+
if len(validate) == 0 || (validate == "false" || validate == "0") {
15+
return true, nil
16+
}
17+
18+
var err error
19+
var found bool
20+
c := http.Client{}
21+
request, _ := http.NewRequest(http.MethodGet, "https://raw.githubusercontent.com/alexellis/derek/master/.CUSTOMERS", nil)
22+
res, doErr := c.Do(request)
23+
if err != nil {
24+
err = doErr
25+
// Not sure how I feel about goto, but seems OK here (Alex Ellis)
26+
goto DO_RETURN
27+
}
28+
29+
if res.Body != nil {
30+
defer res.Body.Close()
31+
body, readErr := ioutil.ReadAll(res.Body)
32+
if readErr != nil {
33+
err = readErr
34+
goto DO_RETURN
35+
}
36+
37+
lines := strings.Split(strings.TrimSpace(string(body)), "\n")
38+
39+
for _, line := range lines {
40+
if line == repo.Owner.Login {
41+
found = true
42+
break
43+
}
44+
}
45+
}
46+
47+
DO_RETURN:
48+
return found, err
49+
}

commentHandler.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@ const closed = "closed"
1919
const maintainersFileEnv = "maintainers_file"
2020
const defaultMaintFile = "MAINTAINERS"
2121

22-
func makeClient() (*github.Client, context.Context) {
22+
func makeClient(installation int) (*github.Client, context.Context) {
2323
ctx := context.Background()
2424

2525
token := os.Getenv("access_token")
2626
if len(token) == 0 {
27-
newToken, tokenErr := auth.MakeAccessTokenForInstallation(os.Getenv("application"), os.Getenv("installation"), os.Getenv("private_key"))
27+
newToken, tokenErr := auth.MakeAccessTokenForInstallation(os.Getenv("application"), installation, os.Getenv("private_key"))
2828
if tokenErr != nil {
2929
log.Fatalln(tokenErr.Error())
3030
}
@@ -59,7 +59,7 @@ func handleComment(req types.IssueCommentOuter) {
5959
}
6060

6161
if allowed {
62-
client, ctx := makeClient()
62+
client, ctx := makeClient(req.Installation.ID)
6363
_, res, err := client.Issues.AddLabelsToIssue(ctx, req.Repository.Owner.Login, req.Repository.Name, req.Issue.Number, []string{command.Value})
6464
if err != nil {
6565
log.Fatalf("%s, limit: %d, remaining: %d", err, res.Limit, res.Remaining)
@@ -87,7 +87,7 @@ func handleComment(req types.IssueCommentOuter) {
8787
}
8888

8989
if allowed {
90-
client, ctx := makeClient()
90+
client, ctx := makeClient(req.Installation.ID)
9191
_, err := client.Issues.RemoveLabelForIssue(ctx, req.Repository.Owner.Login, req.Repository.Name, req.Issue.Number, command.Value)
9292
if err != nil {
9393
log.Fatalln(err)
@@ -101,7 +101,7 @@ func handleComment(req types.IssueCommentOuter) {
101101
fmt.Printf("%s wants to %s user %s to issue %d - allowed? %t\n", req.Comment.User.Login, command.Type, command.Value, req.Issue.Number, allowed)
102102

103103
if allowed {
104-
client, ctx := makeClient()
104+
client, ctx := makeClient(req.Installation.ID)
105105
assignee := command.Value
106106
if assignee == "me" {
107107
assignee = req.Comment.User.Login
@@ -119,7 +119,7 @@ func handleComment(req types.IssueCommentOuter) {
119119
fmt.Printf("%s wants to %s user %s from issue %d - allowed? %t\n", req.Comment.User.Login, command.Type, command.Value, req.Issue.Number, allowed)
120120

121121
if allowed {
122-
client, ctx := makeClient()
122+
client, ctx := makeClient(req.Installation.ID)
123123
assignee := command.Value
124124
if assignee == "me" {
125125
assignee = req.Comment.User.Login
@@ -137,7 +137,7 @@ func handleComment(req types.IssueCommentOuter) {
137137
fmt.Printf("%s wants to %s issue #%d - allowed? %t\n", req.Comment.User.Login, command.Type, req.Issue.Number, allowed)
138138

139139
if allowed {
140-
client, ctx := makeClient()
140+
client, ctx := makeClient(req.Installation.ID)
141141

142142
var state string
143143

derek.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
provider:
2+
name: faas
3+
# gateway: http://localhost:80 # can be a remote server
4+
5+
functions:
6+
the-derek:
7+
handler: ./
8+
image: derek:2.0
9+
lang: Dockerfile
10+
environment:
11+
private_key: derek.pem
12+
validate_hmac: false
13+
debug: true
14+
environment_file:
15+
- secrets.yml
16+
# See secrets.example.yml

main.go

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,18 @@ import (
1010
"github.com/alexellis/derek/types"
1111
)
1212

13+
func hmacValidation() bool {
14+
val := os.Getenv("validate_hmac")
15+
return len(val) > 0 && (val == "1" || val == "true")
16+
}
17+
1318
func main() {
1419
bytesIn, _ := ioutil.ReadAll(os.Stdin)
1520

16-
xHubSignature := os.Getenv("XHubSignature")
17-
if len(xHubSignature) == 0 {
18-
xHubSignature = os.Getenv("Http_X_Hub_Signature")
21+
xHubSignature := os.Getenv("Http_X_Hub_Signature")
22+
if hmacValidation() && len(xHubSignature) == 0 {
23+
log.Fatal("must provide X_Hub_Signature")
24+
return
1925
}
2026

2127
if len(xHubSignature) > 0 {
@@ -26,24 +32,40 @@ func main() {
2632
log.Fatal(err.Error())
2733
return
2834
}
29-
} else if len(os.Getenv("validate_hmac")) > 0 {
30-
log.Fatal("must provide X_Hub_Signature")
3135
}
3236

37+
// HMAC Validated or not turned on.
38+
3339
eventType := os.Getenv("Http_X_Github_Event")
3440
switch eventType {
3541
case "pull_request":
3642
req := types.PullRequestOuter{}
3743
if err := json.Unmarshal(bytesIn, &req); err != nil {
3844
log.Fatalf("Cannot parse input %s", err.Error())
3945
}
46+
47+
customer, err := auth.IsCustomer(req.Repository)
48+
if err != nil {
49+
log.Fatalf("Unable to verify customer: %s/%s", req.Repository.Owner.Login, req.Repository.Name)
50+
} else if !customer {
51+
log.Fatalf("No customer found for: %s/%s", req.Repository.Owner.Login, req.Repository.Name)
52+
}
53+
4054
handlePullRequest(req)
4155
break
4256
case "issue_comment":
4357
req := types.IssueCommentOuter{}
4458
if err := json.Unmarshal(bytesIn, &req); err != nil {
4559
log.Fatalf("Cannot parse input %s", err.Error())
4660
}
61+
62+
customer, err := auth.IsCustomer(req.Repository)
63+
if err != nil {
64+
log.Fatalf("Unable to verify customer: %s/%s", req.Repository.Owner.Login, req.Repository.Name)
65+
} else if !customer {
66+
log.Fatalf("No customer found for: %s/%s", req.Repository.Owner.Login, req.Repository.Name)
67+
}
68+
4769
handleComment(req)
4870
break
4971
default:

pullRequestHandler.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@ func handlePullRequest(req types.PullRequestOuter) {
1818

1919
token := os.Getenv("access_token")
2020
if len(token) == 0 {
21-
newToken, tokenErr := auth.MakeAccessTokenForInstallation(os.Getenv("application"), os.Getenv("installation"), os.Getenv("private_key"))
21+
newToken, tokenErr := auth.MakeAccessTokenForInstallation(
22+
os.Getenv("application"),
23+
req.Installation.ID,
24+
os.Getenv("private_key"))
25+
2226
if tokenErr != nil {
2327
log.Fatalln(tokenErr.Error())
2428
}

0 commit comments

Comments
 (0)