-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
459 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 . |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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." | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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= |
Oops, something went wrong.