Skip to content

Commit

Permalink
Merge pull request #411 from cb22/develop
Browse files Browse the repository at this point in the history
Safety Alerts: GitHub PRs and GitHub issues support
  • Loading branch information
cb22 committed Oct 5, 2022
2 parents 97916f6 + 1172ea6 commit 195aefc
Show file tree
Hide file tree
Showing 13 changed files with 1,045 additions and 1 deletion.
2 changes: 1 addition & 1 deletion Dockerfile
Expand Up @@ -10,7 +10,7 @@ RUN cd /app && python3 -m pip install poetry==1.1.13 pipenv==2022.6.7

# Install this project dependencies
COPY . /app
RUN cd /app && python3 -m pip install -e .
RUN cd /app && python3 -m pip install -e .[github]

ENV LC_ALL=C.UTF-8
ENV LANG=C.UTF-8
Expand Down
14 changes: 14 additions & 0 deletions action.yml
Expand Up @@ -6,6 +6,14 @@ inputs:
description: 'PyUp.io API key'
required: false
default: ''
create-pr:
description: 'Create a PR if Safety finds any vulnerabilities. Only the `file` scan mode is currently supported - combine with Cron based actions to get automatic notifications of new vulnerabilities.'
required: false
default: ''
create-issue:
description: 'Create an issue if Safety finds any vulnerabilities. Only the `file` scan mode is currently supported - combine with Cron based actions to get automatic notifications of new vulnerabilities.'
required: false
default: ''
scan:
description: 'Scan mode to use. One of auto / docker / env / file (defaults to auto)'
required: false
Expand All @@ -30,6 +38,9 @@ inputs:
description: '[Advanced] Any additional arguments to pass to Safety'
required: false
default: ''
repo-token:
required: false
default: ''

outputs:
cli-output:
Expand All @@ -43,13 +54,16 @@ runs:
env:
SAFETY_API_KEY: ${{ inputs.api-key }}
SAFETY_ACTION: true
SAFETY_ACTION_CREATE_PR: ${{ inputs.create-pr }}
SAFETY_ACTION_CREATE_ISSUE: ${{ inputs.create-issue }}
SAFETY_ACTION_SCAN: ${{ inputs.scan }}
SAFETY_ACTION_DOCKER_IMAGE: ${{ inputs.docker-image }}
SAFETY_ACTION_REQUIREMENTS: ${{ inputs.requirements }}
SAFETY_ACTION_CONTINUE_ON_ERROR: ${{ inputs.continue-on-error }}
SAFETY_ACTION_OUTPUT_FORMAT: ${{ inputs.output-format }}
SAFETY_ACTION_ARGS: ${{ inputs.args }}
SAFETY_ACTION_FORMAT: true
GITHUB_TOKEN: ${{ inputs.repo-token }}
COLUMNS: 120

branding:
Expand Down
37 changes: 37 additions & 0 deletions entrypoint.sh
Expand Up @@ -65,6 +65,43 @@ if [ "${SAFETY_ACTION_SCAN}" = "auto" ]; then
fi
fi

# remediation mode
if [ "${SAFETY_ACTION_CREATE_PR}" = "true" ] && [ "${SAFETY_ACTION_CREATE_ISSUE}" = "true" ]; then
echo "[Safety Action] Can only create issues or PRs, not both."
exit 1
fi

if [ "${SAFETY_ACTION_CREATE_PR}" = "true" ] || [ "${SAFETY_ACTION_CREATE_ISSUE}" = "true" ]; then
if [ "${SAFETY_ACTION_SCAN}" != "file" ]; then
echo "[Safety Action] Creating PRs / issues is only supported when scanning a requirements file."
exit 1
fi

# TODO: Add info to env vars for telemetry...

# Build up a list of requirements files, or use SAFETY_ACTION_REQUIREMENTS if that's set.
# This will be moved into Safety proper in the future.
requirement_files=()
if [ -z "${SAFETY_ACTION_REQUIREMENTS}" ]; then
readarray -d '' matches < <(find . -type f -name requirements.txt -print0)
for match in ${matches[@]}; do
requirement_files+=("-r" "${match}")
done
else
requirement_files=("-r" "${SAFETY_ACTION_REQUIREMENTS}")
fi

alert_action="github-pr"
if [ "${SAFETY_ACTION_CREATE_ISSUE}" = "true" ]; then
alert_action="github-issue"
fi

# Continue on error is set because we're using Safety's output here for further processing.
python -m safety check "${requirement_files[@]}" --continue-on-error --output=json ${SAFETY_ACTION_ARGS} | python -m safety alert "${alert_action}" --repo "${GITHUB_REPOSITORY}" --token "${GITHUB_TOKEN}" --base-url "${GITHUB_API_URL}"

exit 0
fi

if [ "${SAFETY_ACTION_SCAN}" = "docker" ]; then
if [[ "${SAFETY_ACTION_DOCKER_IMAGE}" == "" ]]; then
SAFETY_OS_DESCRIPTION="${SAFETY_OS_DESCRIPTION} docker_image_scan"
Expand Down
42 changes: 42 additions & 0 deletions safety/alerts/__init__.py
@@ -0,0 +1,42 @@
import sys
import json
from typing import Any
import click

from dataclasses import dataclass

from . import github
from safety.util import SafetyPolicyFile

@dataclass
class Alert:
report: Any
key: str
policy: Any = None
requirements_files: Any = None

@click.group(help="Send alerts based on the results of a Safety scan.")
@click.option('--check-report', help='JSON output of Safety Check to work with.', type=click.File('r'), default=sys.stdin)
@click.option("--policy-file", type=SafetyPolicyFile(), default='.safety-policy.yml',
help="Define the policy file to be used")
@click.option("--key", envvar="SAFETY_API_KEY",
help="API Key for pyup.io's vulnerability database. Can be set as SAFETY_API_KEY "
"environment variable.", required=True)
@click.pass_context
def alert(ctx, check_report, policy_file, key):
with check_report:
# TODO: This breaks --help for subcommands
try:
safety_report = json.load(check_report)
except json.decoder.JSONDecodeError as e:
click.secho("Error decoding input JSON: {}".format(e.msg), fg='red')
sys.exit(1)

if not 'report_meta' in safety_report:
click.secho("You must pass in a valid Safety Check JSON report", fg='red')
sys.exit(1)

ctx.obj = Alert(report=safety_report, policy=policy_file if policy_file else {}, key=key)

alert.add_command(github.github_pr)
alert.add_command(github.github_issue)

0 comments on commit 195aefc

Please sign in to comment.