Skip to content

Commit

Permalink
initial commmit
Browse files Browse the repository at this point in the history
  • Loading branch information
xprnvd committed Dec 16, 2023
1 parent 03b45e7 commit b4b922c
Show file tree
Hide file tree
Showing 9 changed files with 459 additions and 1 deletion.
22 changes: 22 additions & 0 deletions .github/workflows/go_build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Go Build

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Set up Go 1.x
uses: actions/setup-go@v2
with:
go-version: 1.21.5
- name: Check out code into the Go module directory
uses: actions/checkout@v2
- name: Get dependencies
run: go mod download
- name: Build
run: go build -v .
36 changes: 35 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,35 @@
# PRSafeGuard
# PR-ThreatAware

PR-ThreatAware is a GitHub application developed from the ground up, designed to be installed across GitHub organizations. It efficiently tracks and analyzes pull requests (PRs) within the organization's repositories.

## How it Works

PR-ThreatAware utilizes webhooks to monitor and track PR events. Upon receiving a PR event, it collects essential context surrounding the PR, including details such as the PR description, file changes, commit diffs, user information, and other relevant parameters.

## Security Risk Analysis

The application employs OpenAI's GPT-3.5 Turbo models to evaluate the security risks introduced by each PR. Leveraging these models, it measures and assigns a risk score based on the analysis performed.

## Review Process

If the PR's risk level exceeds a predefined threshold, PR-ThreatAware takes action by adding reviewers from the security team to ensure comprehensive evaluation and mitigation of potential security risks.

## Installation

To install PR-ThreatAware within your GitHub organization, follow these steps:

1. **Clone the Repository:** Clone the PR-ThreatAware repository to a local environment or server that will host the application.
2. **Configure Webhooks:** Set up webhooks in your GitHub organization's repositories to trigger events that communicate with the PR-ThreatAware application. Configure these webhooks to point to the application's designated endpoint.
3. **Configure Permissions:** Ensure that PR-ThreatAware has appropriate permissions to access PR details and assign reviewers. Review and adjust permissions as needed within your GitHub organization settings.

## Configuration

Customize the risk threshold and reviewer assignment logic according to your organization's security policies and requirements. These configurations are adjustable within the designated configuration files provided with the application.

## Contributing

Contributions are welcome! Fork the PR-ThreatAware repository, make necessary changes or enhancements, and submit pull requests to contribute to the application's functionality or resolve identified issues.

## License

This project is licensed under the [MIT License](LICENSE.md).
11 changes: 11 additions & 0 deletions configuration.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package main

const (
PrivateKeyPath = "threataware.2023-12-13.private-key.pem" // used to sign JWT
AppID = 700316
InstallationID = 45095647 // application webhook logs can help identify this
prompt = "Evaluate the security risk introduced in the given PR based on the provided data. The PR contains changes across multiple files in a GitHub repository.Analyze the commits' differences provided in the 'commitsDiff' section and determine the potential security risks introduced or mitigated by this PR. Identify any vulnerabilities such as hardcoded credentials, SQL injection, or other security concerns in the changes made.Provide a critical score out of 100. The output should only be a number, not a sentence."
OpenAIKey = "openaikey.pem" // does not need to be a pem file
securityResearchers = "github username"
botComment = "This PR has been flagged as a security risk. Please review the comments and make any necessary changes. Security researchers have been added as reviewers."
)
71 changes: 71 additions & 0 deletions githubauth.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package main

import (
"context"
"io/ioutil"
"time"

"github.com/golang-jwt/jwt"
"github.com/google/go-github/v57/github"
"golang.org/x/oauth2"
)

func generateJWT(AppID int, PrivateKeyPath string) (string, error) {
privateKey, err := ioutil.ReadFile(PrivateKeyPath)
if err != nil {
return "", err
}

parsedKey, err := jwt.ParseRSAPrivateKeyFromPEM(privateKey)
if err != nil {
return "", err
}

token := jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.MapClaims{
"iat": time.Now().Unix(),
"exp": time.Now().Add(time.Minute * 10).Unix(),
"iss": AppID,
})

tokenString, err := token.SignedString(parsedKey)
if err != nil {
return "", err
}

return tokenString, nil
}

func getInstallationAccessToken(jwt string, InstallationID int64) (string, error) {
ctx := context.Background()
ts := oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: jwt},
)
tc := oauth2.NewClient(ctx, ts)

client := github.NewClient(tc)

token, _, err := client.Apps.CreateInstallationToken(ctx, InstallationID, nil)
if err != nil {
return "", err
}

return token.GetToken(), nil
}

func githubClient() *github.Client {
jwt, err := generateJWT(AppID, PrivateKeyPath)
if err != nil {
panic(err)
}

token, err := getInstallationAccessToken(jwt, InstallationID)
if err != nil {
panic(err)
}
ctx := context.Background()
ts := oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: token},
)
tc := oauth2.NewClient(ctx, ts)
return github.NewClient(tc)
}
127 changes: 127 additions & 0 deletions githubpr.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
package main

import (
"context"
"encoding/json"
"fmt"

"github.com/google/go-github/v57/github"
)

func getPRDetails(client *github.Client, owner string, repo string, number int) string {
pr, _, err := client.PullRequests.Get(context.Background(), owner, repo, number)
if err != nil {
panic(err)
}

files, _, err := client.PullRequests.ListFiles(context.Background(), owner, repo, number, nil)
if err != nil {
panic(err)
}

fileDetails := make([]map[string]interface{}, len(files))
for i, file := range files {
fileDetail := map[string]interface{}{
"filename": *file.Filename,
"additions": *file.Additions,
"deletions": *file.Deletions,
}
fileDetails[i] = fileDetail
}

compareCommitsRaw, _, err := client.Repositories.CompareCommitsRaw(context.Background(), owner, repo, *pr.Base.Ref, *pr.Head.Ref, github.RawOptions{Type: github.Diff})
if err != nil {
panic(err)
}
commitsDiff := string(compareCommitsRaw)

prDescription := *pr.Body
prTitle := *pr.Title
prState := *pr.State
prURL := *pr.HTMLURL
prUser := *pr.User.Login
prBranch := *pr.Head.Ref
prBaseBranch := *pr.Base.Ref
prDiffURL := *pr.DiffURL

if prState == "closed" {
return "skip"
}
if prDescription == "" {
prDescription = "No description"
}
if prTitle == "" {
prTitle = "No title"
}

prJSON := map[string]interface{}{
"description": prDescription,
"title": prTitle,
"state": prState,
"url": prURL,
"user": prUser,
"branch": prBranch,
"baseBranch": prBaseBranch,
"diffURL": prDiffURL,
"files": fileDetails,
"commitsDiff": commitsDiff,
}

jsonData, err := json.Marshal(prJSON)
if err != nil {
fmt.Println("Error:", err)
}

fmt.Println(string(jsonData))

return string(jsonData)
}

func AddLabelsToIssue(client *github.Client, owner string, repo string, number int, labels []string) error {
_, _, err := client.Issues.AddLabelsToIssue(context.Background(), owner, repo, number, labels)
if err != nil {
return err
}

fmt.Println("Added labels to issue:", owner, repo, number)
return nil
}

func RemoveLabelFromIssue(client *github.Client, owner string, repo string, number int, label string) error {
_, err := client.Issues.RemoveLabelForIssue(context.Background(), owner, repo, number, label)
if err != nil {
return err
}

fmt.Println("Removed labels from issue:", owner, repo, number)
return nil
}

func AddReviewersToPR(client *github.Client, owner string, repo string, number int, reviewers []string) error {
_, _, err := client.PullRequests.RequestReviewers(context.Background(), owner, repo, number, github.ReviewersRequest{Reviewers: reviewers})
if err != nil {
return err
}

fmt.Println("Added reviewers to PR:", owner, repo, number)
return nil
}

func AddCommntToPR(client *github.Client, owner string, repo string, number int, comment string) error {
_, _, err := client.Issues.CreateComment(context.Background(), owner, repo, number, &github.IssueComment{
Body: &comment,
})
if err != nil {
return err
}

fmt.Println("Added comment to PR:", owner, repo, number)
return nil
}

func handlePR(user string, repo string, prNumber int) (string, string, int, error) {
fmt.Println("Webhook received for PR")
fmt.Printf("Repo: %s, Owner: %s, PR Number: %d\n", repo, user, prNumber)

return user, repo, prNumber, nil
}
19 changes: 19 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
module github.com/raxpd/threataware

go 1.21.5

require (
github.com/golang-jwt/jwt v3.2.2+incompatible
github.com/google/go-github/v57 v57.0.0
golang.org/x/oauth2 v0.15.0
)

require (
github.com/golang-jwt/jwt/v5 v5.2.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/go-github v17.0.0+incompatible // indirect
github.com/google/go-querystring v1.1.0 // indirect
golang.org/x/net v0.19.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.31.0 // indirect
)
19 changes: 19 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
github.com/google/go-github/v57 v57.0.0 h1:L+Y3UPTY8ALM8x+TV0lg+IEBI+upibemtBD8Q9u7zHs=
github.com/google/go-github/v57 v57.0.0/go.mod h1:s0omdnye0hvK/ecLvpsGfJMiRt85PimQh4oygmLIxHw=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ=
golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
Loading

0 comments on commit b4b922c

Please sign in to comment.