Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GitHub enterprise support, PEP 8 refactor, better logging and file handling #19

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# Custom
scan.log
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
Expand Down
51 changes: 34 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,55 @@
</p>

# GitHub Workflow Auditor

Workflow auditing tools to identify security issues in GitHub workflows

# Usage
## Description
GitHub Workflow Auditor identifies vulnerability in GitHub Workflows. It does so by scanning the workflow files for anti-patterns such as ingesting user inputs in an unsafe manner or using malicious commits in build process. The tool supports scanning individual repositories or all accessibe repositories of a user or organization. The output of the scan is saved as `scan.log`.

## Usage

```
usage: main.py [-h] [--type {repo,org,user}] [--log-level {debug,info,warning,error,critical}] input
usage: ghwfauditor [-h] [--endpoint ENDPOINT] [--token TOKEN] [--log-level {debug,info,warning,error,critical}] [--type {repo,org,user}] input

Identify vulnerabilities in GitHub Actions workflow
Identify vulnerabilities in GitHub Actions workflow.

positional arguments:
input User/Org Name or Repo name (owner/repo).
input Organization, repository or user name.

optional arguments:
-h, --help show this help message and exit
options:
-h, --help show this help message and exit.
--endpoint ENDPOINT GitHub endpoint to use.
--token TOKEN GitHub token. Can be provided with environment variable GITHUB_TOKEN.
--log-level {debug,info,warning,error,critical}
Level of debug you wish to display.
--type {repo,org,user}
Type of entity that is being scanned.
--log-level {debug,info,warning,error,critical}
Log level for output
```

Example:
* org - `python3 main.py --type org google`
* user - `python3 main.py --type user test_user`
* repo: `python3 main.py --type repo TinderSec/gh-workflow-auditor`
### Examples

* org - `ghwfauditor --type org google`
* user - `ghwfauditor --type user test_user`
* repo - `ghwfauditor --type repo TinderSec/gh-workflow-auditor`
* enterprise instance - `ghwfauditor --endpoint https://github.tinder.com --type user test_user`

# Setup
## Setup

GitHub Workflow Auditor uses GitHub's GraphQL endoint. Due to this, an API token is required. The program will read it from the `PAT` environment variable. You can generate a basic PAT token (https://github.com/settings/tokens/new) without any scope. Note that you may have to "Configure SSO" for the token to be usable on some organizations.
> :information_source: We recommend using `pipx` over `pip` for system-wide installations.

```shell
pipx install 'git+https://github.com/TinderSec/gh-workflow-auditor.git'
```
export PAT=ghp_YOUR_TOKEN

```shell
pip install 'ghwfauditor@git+https://github.com/TinderSec/gh-workflow-auditor.git'
```


GitHub Workflow Auditor uses GitHub's GraphQL endoint. Due to this, an API token is required. The program will read it from the `--token` argument or in the `GITHUB_TOKEN` environment variable. You can [generate a basic Personal Access Token](https://github.com/settings/tokens/new) without any scope. Note that you may have to "Configure SSO" for the token to be usable on some organizations.

```
export GITHUB_TOKEN=ghp_YOUR_TOKEN
```

# About
GitHub Workflow Auditor identifies vulnerability in GitHub Workflows. It does so by scanning the workflow files for anti-patterns such as ingesting user inputs in an unsafe manner or using malicious commits in build process. The tool supports scanning individual repositories or all accessibe repositories of a user or organization. The output of the scan is saved as `scan.log`.
33 changes: 0 additions & 33 deletions action_auditor.py

This file was deleted.

106 changes: 0 additions & 106 deletions auditor.py

This file was deleted.

12 changes: 12 additions & 0 deletions ghwfauditor/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/usr/bin/env python3

# Local imports
from ghwfauditor import console


def main() -> None:
console.run()


if __name__ == "__main__":
main()
58 changes: 58 additions & 0 deletions ghwfauditor/action_auditor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Built-in imports
import re
from pathlib import Path


class ActionAuditor:
"""Class used to audit GitHub actions

Attributes:
logger: Configured logger.
gh_wrapper (GHWrapper): Object handling the connection to the GitHub API.
action_file: Temporary file used to store potentially vulnerable results.

"""

def __init__(self, logger, gh_wrapper, action_file):
"""ActionAuditor constructor

Arguments:
logger: Configured logger.
gh_wrapper (GHWrapper): Object handling the connection to the GitHub API.
action_file: Temporary file used to store actions.

"""
self.logger = logger
self.gh = gh_wrapper
self.action_file = action_file

def check_usernames(self, username_list):
for username in username_list:
renamed_or_not = self.gh.stale_checker(username=username)
if not renamed_or_not:
self.logger.success(
f"Security Issue: Supply chain. {username} was renamed but used in workflows. Signup the username to make sure."
)

def action_audit(self):
"""Check that action file still exists and audit content"""
if Path(self.action_file.name).exists():
usernames = self.read_actions_file()
self.check_usernames(usernames)
else:
self.logger.error(
"The temporary file has been deleted by an external program"
)

def read_actions_file(self):
"""Read action file and return a list of username"""
array_of_usernames = []
self.action_file.seek(0)
lines = self.action_file.readlines()
for line in lines:
username = line.split("/")[0]
username_regex = re.compile("[A-Za-z0-9-]*")
if username_regex.fullmatch(username):
if username not in array_of_usernames:
array_of_usernames.append(username)
return array_of_usernames
File renamed without changes.
Loading