Skip to content

Commit

Permalink
feat: validate webhook secret
Browse files Browse the repository at this point in the history
  • Loading branch information
la3rence committed Mar 9, 2021
1 parent 5c11993 commit 08a2e32
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 29 deletions.
25 changes: 14 additions & 11 deletions README.md
Expand Up @@ -3,12 +3,13 @@

# OpsBot 🤖️

A robot based on GitHub sdk and [Vercel's Serverless Function (Go)](https://vercel.com/docs/runtimes#official-runtimes/go).
It acts like the [Kubernetes Prow Robot](https://github.com/k8s-ci-robot). The robot manages your GitHub repo's issues and
pull requests by the content of comments that the user sends.
A robot based on GitHub sdk
and [Vercel's Serverless Function (Go)](https://vercel.com/docs/runtimes#official-runtimes/go). It acts like
the [Kubernetes Prow Robot](https://github.com/k8s-ci-robot). The robot manages your GitHub repo's issues and pull
requests by the content of comments that the user sends.

This project is just getting start and is a toy tool now. For the effectiveness, you can check out any issue or pr from this repo.
If you're interested in this stuff as well, issues or pull requests are welcomed.
This project is just getting start and is a toy tool now. For the effectiveness, you can check out any issue or pr from
this repo. If you're interested in this stuff as well, issues or pull requests are welcomed.

## Roadmap / Usage

Expand All @@ -25,14 +26,16 @@ If you're interested in this stuff as well, issues or pull requests are welcomed

[Deploy this on Vercel](https://go.lawrenceli.me/deploy-opsbot)

Go to GitHub Repository -> Settings -> WebHook. Add a new WebHook, check `application/json`
and choose all events(or events you care about). Input Payload URL (WebHook Serverless Function API),
such as `https://your-username.vercel.app/api/index`
Go to GitHub Repository -> Settings -> WebHook. Add a new WebHook, check `application/json`
and choose all events(or events you care about). Input Payload URL (WebHook Serverless Function API), such
as `https://your-username.vercel.app/api/index`. Protect this webhook by using secret with any string.

Register a new GitHub account (as the robot) and [create its personal access token](https://github.com/settings/tokens/new)
Don't forget to config the `BOT_TOKEN` as the production environment variable and invite it as your repo's collaborator.
Register a new GitHub account (as the robot)
and [create its personal access token](https://github.com/settings/tokens/new). Don't forget to config the `BOT_TOKEN`
and the `WEBHOOK_SECRET` as the production environment variable and invite it as your repo's collaborator.

For more information you can [contact the author](https://go.lawrenceli.me/contact)
For more information you can [contact the author](https://go.lawrenceli.me/contact) or open an issue.

## License

MIT
38 changes: 20 additions & 18 deletions api/index.go
Expand Up @@ -6,7 +6,6 @@ import (
"fmt"
"github.com/google/go-github/github"
"golang.org/x/oauth2"
"io/ioutil"
"log"
"net/http"
"os"
Expand All @@ -23,6 +22,7 @@ const (
)

var ctx = context.Background()
var secret = os.Getenv("WEBHOOK_SECRET")

func getGitHubClient() *github.Client {
token := os.Getenv("BOT_TOKEN")
Expand All @@ -33,16 +33,18 @@ func getGitHubClient() *github.Client {
return github.NewClient(tc)
}

// this Handler used to be the serverless function
func Handler(w http.ResponseWriter, r *http.Request) {
payload, err := ioutil.ReadAll(r.Body)
if err != nil {
log.Printf("error reading request body: err=%s\n", err)
payload, validateErr := github.ValidatePayload(r, []byte(secret))
if validateErr != nil {
http.Error(w, "The GitHub signature header is invalid.", http.StatusUnauthorized)
log.Printf("invalid signature: %s\n", validateErr.Error())
return
}
defer r.Body.Close()
event, err := github.ParseWebHook(github.WebHookType(r), payload)
if err != nil {
log.Printf("could not parse webhook: err=%s\n", err)
event, parseErr := github.ParseWebHook(github.WebHookType(r), payload)
if parseErr != nil {
http.Error(w, "The payload parsed failed", http.StatusInternalServerError)
log.Printf("could not parse webhook: %s\n", parseErr)
return
}
githubClient := getGitHubClient()
Expand All @@ -63,31 +65,31 @@ func Handler(w http.ResponseWriter, r *http.Request) {
commentBody := e.GetComment().GetBody()
if action == "edited" || action == "created" {
issueCommentEvent := *e
if strings.Contains(commentBody, Close) {
closeOrOpenIssue(githubClient, issueCommentEvent, false)
if strings.Contains(commentBody, Label) {
addLabelsToIssue(commentBody, githubClient, issueCommentEvent)
}
if strings.Contains(commentBody, Reopen) {
closeOrOpenIssue(githubClient, issueCommentEvent, true)
if strings.Contains(commentBody, UnLabel) {
removeLabelFromIssue(commentBody, githubClient, issueCommentEvent)
}
if strings.Contains(commentBody, Approve) {
approvePullRequest(githubClient, issueCommentEvent)
}
if strings.Contains(commentBody, LGTM) {
mergePullRequest(githubClient, issueCommentEvent)
}
if strings.Contains(commentBody, Label) {
addLabelsToIssue(commentBody, githubClient, issueCommentEvent)
if strings.Contains(commentBody, Close) {
closeOrOpenIssue(githubClient, issueCommentEvent, false)
}
if strings.Contains(commentBody, UnLabel) {
removeLabelFromIssue(commentBody, githubClient, issueCommentEvent)
if strings.Contains(commentBody, Reopen) {
closeOrOpenIssue(githubClient, issueCommentEvent, true)
}
}
default:
log.Printf("unknown event type %s\n", github.WebHookType(r))
_, err = fmt.Fprintf(w, "ok")
_, _ = fmt.Fprintf(w, "ok")
return
}
_, err = fmt.Fprintf(w, "ok")
_, _ = fmt.Fprintf(w, "ok")
}

func approvePullRequest(client *github.Client, event github.IssueCommentEvent) {
Expand Down

1 comment on commit 08a2e32

@vercel
Copy link

@vercel vercel bot commented on 08a2e32 Mar 9, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.