Skip to content

Commit

Permalink
make the code public
Browse files Browse the repository at this point in the history
  • Loading branch information
R3x committed Aug 9, 2023
1 parent 41d1df1 commit d4464d6
Show file tree
Hide file tree
Showing 84 changed files with 7,777 additions and 0 deletions.
26 changes: 26 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
FROM python:3.10

WORKDIR /root

# Install dependencies
RUN apt-get -y update
RUN apt-get -y install python3-poetry nodejs
RUN mkdir codeql_home

# Setup codeql
WORKDIR /root/codeql_home
RUN mkdir codeql-repo
RUN git clone --depth 1 https://github.com/github/codeql codeql-repo/
RUN wget https://github.com/github/codeql-cli-binaries/releases/download/v2.13.3/codeql-linux64.zip
RUN unzip codeql-linux64.zip

# Copy argus files and queries
COPY argus.py poetry.lock pyproject.toml /root/
COPY argus_components /root/argus_components
COPY qlqueries /root/qlqueries
RUN poetry install

# Now run argus
WORKDIR /root
RUN mkdir results
ENTRYPOINT ["poetry", "run", "python3", "argus.py"]
82 changes: 82 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Argus

This repo contains the code for our USENIX Security '23 paper "ARGUS: A Framework for Staged Static Taint Analysis of GitHub Workflows and Actions". Argus is a comprehensive security analysis tool specifically designed for GitHub Actions. Built with an aim to enhance the security of CI/CD workflows, Argus utilizes taint-tracking techniques and an impact classifier to detect potential vulnerabilities in GitHub Action workflows.

## Features

- **Taint-Tracking**: Argus uses sophisticated algorithms to track the flow of potentially untrusted data from specific sources to security-critical sinks within GitHub Actions workflows. This enables the identification of vulnerabilities that could lead to code injection attacks.

- **Impact Classifier**: Argus classifies identified vulnerabilities into High, Medium, and Low severity classes, providing a clearer understanding of the potential impact of each identified vulnerability. This is crucial in prioritizing mitigation efforts.

## Usage

This Python script provides a command line interface for interacting with GitHub repositories and GitHub actions.

```bash
python argus.py --mode [mode] --url [url] [--output-folder path_to_output] [--config path_to_config] [--verbose] [--branch branch_name] [--commit commit_hash] [--tag tag_name] [--action-path path_to_action] [--workflow-path path_to_workflow]
```

### Parameters:

- `--mode`: The mode of operation. Choose either 'repo' or 'action'. This parameter is required.
- `--url`: The GitHub URL. Use `USERNAME:TOKEN@URL` for private repos. This parameter is required.
- `--output-folder`: The output folder. The default value is '/tmp'. This parameter is optional.
- `--config`: The config file. This parameter is optional.
- `--verbose`: Verbose mode. If this option is provided, the logging level is set to DEBUG. Otherwise, it is set to INFO. This parameter is optional.
- `--branch`: The branch name. You must provide exactly one of: `--branch`, `--commit`, `--tag`. This parameter is optional.
- `--commit`: The commit hash. You must provide exactly one of: `--branch`, `--commit`, `--tag`. This parameter is optional.
- `--tag`: The tag. You must provide exactly one of: `--branch`, `--commit`, `--tag`. This parameter is optional.
- `--action-path`: The (relative) path to the action. You cannot provide `--action-path` in repo mode. This parameter is optional.
- `--workflow-path`: The (relative) path to the workflow. You cannot provide `--workflow-path` in action mode. This parameter is optional.

### Example:

To use this script to interact with a GitHub repo, you might run a command like the following:

```bash
python argus.py --mode repo --url https://github.com/username/repo.git --branch master
```

This would run the script in repo mode on the master branch of the specified repository.

### How to use

Argus can be run inside a docker container. To do so, follow the steps:
- Install docker and docker-compose
- apt-get -y install docker.io docker-compose
- Clone the release branch of this repo
- git clone <>
- Build the docker container
- docker-compose build
- Now you can run argus. Example run:
- docker-compose run argus --mode {mode} --url {url to target repo}
- Results will be available inside the `results` folder

## Viewing SARIF Results

You can view SARIF results either through an online viewer or with a Visual Studio Code (VSCode) extension.

1. **Online Viewer:** The [SARIF Web Viewer](https://microsoft.github.io/sarif-web-component/) is an online tool that allows you to visualize SARIF files. You can upload your SARIF file (`argus_report.sarif`) directly to the website to view the results.

2. **VSCode Extension:** If you prefer to use VSCode, you can install the [SARIF Viewer](https://marketplace.visualstudio.com/items?itemName=MS-SarifVSCode.sarif-viewer) extension. After installing the extension, you can open your SARIF file (`argus_report.sarif`) in VSCode. The results will appear in the SARIF Explorer pane, which provides a detailed and navigable view of the results.

Remember to handle the SARIF file with care, especially if it contains sensitive information from your codebase.

## Troubleshooting

If there is an issue with needing the Github authorization for running, you can provide `username:TOKEN` in the `GITHUB_CREDS` environment variable. This will be used for all the requests made to Github. Note, we do not store this information anywhere, neither create any thing in the Github account - we only use this for cloning the repositories.

## Contributions

Argus is an open-source project, and we welcome contributions from the community. Whether it's reporting a bug, suggesting a feature, or writing code, your contributions are always appreciated!

## Cite Argus

If you use Argus in your research, please cite our paper:

```
```

## License

Argus is licensed under GPL License.
84 changes: 84 additions & 0 deletions argus.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# _____ __________ ________ ____ ___ _________
# / _ \\______ \/ _____/| | \/ _____/
# / /_\ \| _/ \ ___| | /\_____ \
# / | \ | \ \_\ \ | / / \
# \____|__ /____|_ /\______ /______/ /_______ /
# \/ \/ \/ \/
#
# Copyright (C) 2023 Siddharth Muralee

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.

import click
import logging

import argus_components
from argus_components.common.config import parse_config
from argus_components.common.pylogger import set_global_log_level

@click.command()
@click.option("--mode", type=click.Choice(['repo', 'action']), required=True, help="The mode of operation. Choose either 'repo' or 'action'.")
@click.option("--url", required=True, type=str, help="The GitHub URL. use USERNAME:TOKEN@URL for private repos.")
@click.option("--output-folder", required=False, default="/tmp", help="The output folder.", type=click.Path(exists=True))
@click.option("--config", required=False, default=None, help="The config file.", type=click.Path(exists=True))
@click.option("--verbose", is_flag=True, default=False, help="Verbose mode.")
@click.option("--branch", default=None, type=str, help="The branch name.")
@click.option("--commit", default=None, type=str, help="The commit hash.")
@click.option("--tag", default=None, type=str, help="The tag.")
@click.option("--action-path", default=None, type=str, help="The (relative) path to the action.")
@click.option("--workflow-path", default=None, type=str, help="The (relative) path to the workflow.")
def main(mode, url, branch, commit, tag, output_folder, config, verbose, action_path, workflow_path):

if verbose:
set_global_log_level(logging.DEBUG)
else:
set_global_log_level(logging.INFO)

options = [branch, commit, tag]
options_names = ['branch', 'commit', 'tag']
num_of_options_provided = sum(option is not None for option in options)

if num_of_options_provided > 1:
raise click.BadParameter("You must provide exactly one of: --branch, --commit, --tag")

option_provided, option_value = next(((name, value) for name, value in zip(options_names, options) if value is not None), (None, None))

if config:
parse_config(config)

option_dict = {
"type": option_provided,
"value": option_value
} if option_provided and option_value else {}

if mode == "repo":
if action_path:
raise click.BadParameter("You cannot provide --action-path in repo mode.")

repo = argus_components.Repo(url, option_dict)
repo.run(workflow_path)
# repo.print_report()
repo.save_report_to_file()
elif mode == "action":
if workflow_path:
raise click.BadParameter("You cannot provide --workflow-path in action mode.")

action = argus_components.Action(url, option_dict, action_path)
action.run()
# action.print_report()
action.save_report_to_file()


if __name__ == "__main__":
main()
24 changes: 24 additions & 0 deletions argus_components/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# _____ __________ ________ ____ ___ _________
# / _ \\______ \/ _____/| | \/ _____/
# / /_\ \| _/ \ ___| | /\_____ \
# / | \ | \ \_\ \ | / / \
# \____|__ /____|_ /\______ /______/ /_______ /
# \/ \/ \/ \/
#
# Copyright (C) 2023 Siddharth Muralee

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.

from .action import Action
from .repo import Repo
87 changes: 87 additions & 0 deletions argus_components/action.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# _____ __________ ________ ____ ___ _________
# / _ \\______ \/ _____/| | \/ _____/
# / /_\ \| _/ \ ___| | /\_____ \
# / | \ | \ \_\ \ | / / \
# \____|__ /____|_ /\______ /______/ /_______ /
# \/ \/ \/ \/
#
# Copyright (C) 2023 Siddharth Muralee

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
from urllib.parse import urlparse

from argus_components.common.config import LOCAL_FOLDER, RESULTS_FOLDER
from argus_components.common.pylogger import get_logger
from argus_components.common.githandler import clone_repo

from argus_components.plugins import GHAction

logger = get_logger("repo")

class Action:
LOCAL_ACTION = 1
REMOTE_ACTION = 2

def __init__(self, action_url, options_dict, action_path, action_type = REMOTE_ACTION):
self.action_url = action_url
self.options_dict = options_dict
self.action_path = action_path
self.action_type = action_type

if self.action_type == self.REMOTE_ACTION and "github.com" not in self.action_url:
raise Exception("Only GitHub Actions are supported for now")

if self.action_type == self.LOCAL_ACTION:
pass
elif self.action_type == self.REMOTE_ACTION:
self.action_name = self._get_action_name_from_url()
self.name = self.action_name.replace("#", "/")
else:
raise Exception("Invalid action type")

logger.info(f"Initialzed Action : {self.action_name}")

def run(self):
if self.action_type == self.LOCAL_ACTION:
self._run_local_action()
elif self.action_type == self.REMOTE_ACTION:
self._run_remote_action()

def _run_local_action(self):
pass

def _run_remote_action(self):
folder = LOCAL_FOLDER / self.action_name
logger.info(f"Cloning action to {folder}")
# clone the repository
clone_repo(self.action_url, folder, self.options_dict)
# Get action Object
action_obj = GHAction.identify_action(self.name, self.action_path, folder, self)
self.report = action_obj.run()

def _get_action_name_from_url(self):
# https://github.com/repo/action_name/optional_path/optional_path2
# need to return action_name
# let's get both the repo name and the action name
path = urlparse(self.action_url).path
repo, action = path.split("/")[1], path.split("/")[2]

return repo + "#" + action

def save_report_to_file(self):
file_name = RESULTS_FOLDER / f"{self.action_name}_{self.options_dict['value']}.sarif"
return self.report.get_report(file_name)

def print_report(self):
return self.report.get_report(None)
23 changes: 23 additions & 0 deletions argus_components/ci/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# _____ __________ ________ ____ ___ _________
# / _ \\______ \/ _____/| | \/ _____/
# / /_\ \| _/ \ ___| | /\_____ \
# / | \ | \ \_\ \ | / / \
# \____|__ /____|_ /\______ /______/ /_______ /
# \/ \/ \/ \/
#
# Copyright (C) 2023 Siddharth Muralee

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.

from .github import GithubCI
Loading

0 comments on commit d4464d6

Please sign in to comment.