diff --git a/.github/scripts/setup-env.sh b/.github/scripts/setup-env.sh new file mode 100755 index 0000000..8144c8f --- /dev/null +++ b/.github/scripts/setup-env.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +# +# Environment setup script for the local project. Intended to be used with automation +# to create a repeatable local environment for tests to be run in. The python env +# this script creates can be accessed at the location defined by the CI_VENV variable +# below. + +set -e; + +CI_CACHE=$HOME/.cache; +POETRY_VERSION=1.1.12; + +mkdir --parents "$CI_CACHE"; + +command -v python; +python --version; + +curl --location https://install.python-poetry.org \ + --output "$CI_CACHE/install-poetry.py" \ + --silent \ + --show-error; +python "$CI_CACHE/install-poetry.py" \ + --version "$POETRY_VERSION" \ + --yes; +poetry --version --no-ansi; +poetry run pip --version; + +poetry install \ + --extras poetry \ + --quiet \ + --remove-untracked \ + --no-ansi; + +poetry env info; +poetry run tox --version; diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..a880184 --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,76 @@ +--- +name: CI +on: + pull_request: + types: ["opened", "synchronize"] + push: + branches: ["devel"] +jobs: + Test: + runs-on: ubuntu-latest + strategy: + matrix: + python: + - version: "3.6" + toxenv: py36 + - version: "3.7" + toxenv: py37 + - version: "3.8" + toxenv: py38 + - version: "3.9" + toxenv: py39 + - version: "3.10" + toxenv: py310 + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Install Python ${{ matrix.python.version }} + uses: actions/setup-python@v1 + with: + python-version: ${{ matrix.python.version }} + - name: Configure Job Cache + uses: actions/cache@v2 + with: + path: | + ~/.cache/pip + ~/.cache/pypoetry/cache + ~/.poetry + # Including the hashed poetry.lock in the cache slug ensures that the cache + # will be invalidated, and thus all packages will be redownloaded, if the + # lockfile is updated + key: ${{ runner.os }}-${{ matrix.python.toxenv }}-${{ hashFiles('**/poetry.lock') }} + - name: Configure Path + run: echo "$HOME/.local/bin" >> $GITHUB_PATH + - name: Configure Environment + run: .github/scripts/setup-env.sh + - name: Run Toxenv ${{ matrix.python.toxenv }} + run: poetry run tox -e ${{ matrix.python.toxenv }} + Check: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Install Python 3.8 + uses: actions/setup-python@v1 + with: + python-version: 3.8 + - name: Configure Job Cache + uses: actions/cache@v2 + with: + path: | + ~/.cache/pip + ~/.cache/pypoetry/cache + ~/.poetry + # Hardcoded 'py38' slug here lets this cache piggyback on the 'py38' cache + # that is generated for the tests above + key: ${{ runner.os }}-py38-${{ hashFiles('**/poetry.lock') }} + - name: Configure Path + run: echo "$HOME/.local/bin" >> $GITHUB_PATH + - name: Configure Environment + run: .github/scripts/setup-env.sh + - name: Run Static Analysis Checks + run: poetry run tox -e static + - name: Run Static Analysis Checks (Tests) + run: poetry run tox -e static-tests + - name: Run Security Checks + run: poetry run tox -e security diff --git a/tox.ini b/tox.ini index 07e0a01..669c64c 100644 --- a/tox.ini +++ b/tox.ini @@ -12,7 +12,10 @@ locked_deps = pytest-cov toml commands = - pytest --cov vault2vault --cov-config {toxinidir}/.coveragerc --cov-report term-missing {toxinidir}/tests/ + pytest {toxinidir}/tests/ \ + --cov vault2vault \ + --cov-config {toxinidir}/.coveragerc \ + --cov-report term-missing [testenv:static] description = Static formatting and quality enforcement @@ -29,10 +32,15 @@ locked_deps = pre-commit pre-commit-hooks pylint + types-toml commands = - pre-commit run --all-files - pylint --rcfile {toxinidir}/.pylintrc {toxinidir}/vault2vault.py - mypy --ignore-missing-imports --no-strict-optional {toxinidir}/vault2vault.py + pre-commit run \ + --all-files + pylint {toxinidir}/vault2vault.py \ + --rcfile {toxinidir}/.pylintrc + mypy {toxinidir}/vault2vault.py \ + --ignore-missing-imports \ + --no-strict-optional [testenv:static-tests] description = Static formatting and quality enforcement for the tests @@ -43,21 +51,37 @@ locked_deps = pylint pytest mypy + types-toml commands = - pylint --rcfile {toxinidir}/.pylintrc {toxinidir}/tests/ - mypy --ignore-missing-imports --no-strict-optional {toxinidir}/tests/ + pylint {toxinidir}/tests/ \ + --rcfile {toxinidir}/.pylintrc + mypy {toxinidir}/tests/ \ + --ignore-missing-imports \ + --no-strict-optional [testenv:security] description = Security checks basepython = python3.8 platform = linux ignore_errors = true +skip_install = true locked_deps = bandit safety poetry commands = - bandit --recursive --quiet {toxinidir}/vault2vault.py - bandit --recursive --quiet --skip B101 {toxinidir}/tests/ - poetry export --format requirements.txt --output {envtmpdir}/requirements.txt --without-hashes --dev - safety check --bare --file {envtmpdir}/requirements.txt + bandit {toxinidir}/vault2vault.py \ + --recursive \ + --quiet + bandit {toxinidir}/tests/ \ + --recursive \ + --quiet \ + --skip B101 + poetry export \ + --format requirements.txt \ + --output {envtmpdir}/requirements.txt \ + --without-hashes \ + --dev + safety check \ + --file {envtmpdir}/requirements.txt \ + --json