diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml deleted file mode 100644 index 36d42e6..0000000 --- a/.github/workflows/ci.yaml +++ /dev/null @@ -1,129 +0,0 @@ -name: CI - -on: - push: - branches: - # only on merges to master branch - - master - # and version branches, which only include minor versions (eg: v3.4) - - v[0-9]+.[0-9]+ - tags: - # also version tags, which include bugfix releases (eg: v3.4.0) - - v[0-9]+.[0-9]+.[0-9]+ - pull_request: - type: [opened, reopened, edited] - branches: - # Only for PRs targeting those branches - - master - - v[0-9]+.[0-9]+ - schedule: - # run every night at midnight - - cron: '0 0 * * *' - - -jobs: - # Special job which automatically cancels old runs for the same branch, prevents runs for the - # same file set which has already passed, etc. - pre_job: - name: Skip Duplicate Jobs Pre Job - runs-on: ubuntu-20.04 - outputs: - should_skip: ${{ steps.skip_check.outputs.should_skip }} - steps: - - id: skip_check - uses: fkirc/skip-duplicate-actions@4c656bbdb6906310fa6213604828008bc28fe55d # v3.3.0 - with: - cancel_others: 'true' - github_token: ${{ github.token }} - - lint-tests: - needs: pre_job - if: "${{ needs.pre_job.outputs.should_skip != 'true' }}" - name: 'Lint checks - ${{ matrix.python-version }}' - runs-on: ubuntu-20.04 - strategy: - fail-fast: false - matrix: - include: - - python-version: 2.7 - tox-env: lint - - python-version: 3.6 - tox-env: lint - steps: - - name: Checkout repository - uses: actions/checkout@v2 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Install tox - run: | - python -m pip install --upgrade pip - pip install tox - - name: Run tests - run: | - tox -e ${{ matrix.tox-env }} - - unit-tests: - needs: pre_job - if: "${{ needs.pre_job.outputs.should_skip != 'true' }}" - name: 'Unit tests - ${{ matrix.python-version }}' - runs-on: ubuntu-20.04 - strategy: - fail-fast: false - matrix: - include: - - python-version: 2.7 - tox-env: py27 - - python-version: 3.6 - tox-env: py36 - steps: - - name: Checkout repository - uses: actions/checkout@v2 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Install tox - run: | - python -m pip install --upgrade pip - pip install tox - - name: Run tests - run: | - tox -e ${{ matrix.tox-env }} - - integration-tests: - needs: pre_job - if: "${{ needs.pre_job.outputs.should_skip != 'true' }}" - name: 'Integration tests - ${{ matrix.python-version }}' - runs-on: ubuntu-20.04 - strategy: - fail-fast: false - matrix: - include: - - python-version: 2.7 - - python-version: 3.6 - steps: - - name: Checkout repository - uses: actions/checkout@v2 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Install tox - run: | - python -m pip install --upgrade pip - pip install tox - - name: Run vagrant - run: | - sudo wget -nv https://releases.hashicorp.com/vagrant/2.2.7/vagrant_2.2.7_x86_64.deb - sudo dpkg -i vagrant_2.2.7_x86_64.deb - sudo rm /opt/vagrant/embedded/bin/ruby - sudo ln -s `which ruby` /opt/vagrant/embedded/bin/ruby - vagrant up - - name: Run tests - run: | - tox -e integration - env: - VAULT_TOKEN: st2token - VAULT_ADDR: http://127.0.0.1:8200 diff --git a/.github/workflows/tox.yaml b/.github/workflows/tox.yaml new file mode 100644 index 0000000..4be0256 --- /dev/null +++ b/.github/workflows/tox.yaml @@ -0,0 +1,117 @@ +name: Tox CI + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v4 + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: "3.8" + + - name: Install tox + run: pip install --user tox + + - name: Lint + run: tox -e lint + + unit-tests: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ["3.8", "3.9", "3.10", "3.11"] + steps: + - name: Checkout repo + uses: actions/checkout@v4 + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Install tox + run: pip install --user tox + + - name: Select tox env + id: tox-env + run: echo tox-env=py${{ matrix.python-version }}-unit | tr -d '.' >> ${GITHUB_OUTPUT} + + - name: Run Unit Tests + run: tox -e ${{ steps.tox-env.outputs.tox-env }} + + integration-tests: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ["3.8", "3.9", "3.10", "3.11"] + services: + vault: + image: hashicorp/vault:1.14.8 + ports: + - 8200:8200 + env: + VAULT_DEV_ROOT_TOKEN_ID: st2token + + steps: + - name: Checkout repo + uses: actions/checkout@v4 + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Install tox + run: pip install --user tox + + - name: Select tox env + id: tox-env + run: echo tox-env=py${{ matrix.python-version }}-integration | tr -d '.' >> ${GITHUB_OUTPUT} + + - name: Run Integration Tests + run: tox -e ${{ steps.tox-env.outputs.tox-env }} + env: + VAULT_TOKEN: st2token + VAULT_ADDR: http://127.0.0.1:8200 + + set_merge_ok: + name: Set Merge OK + if: always() && !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled') + needs: + - lint + - unit-tests + - integration-tests + outputs: + merge_ok: ${{ steps.set_merge_ok.outputs.merge_ok }} + runs-on: ubuntu-latest + steps: + - id: set_merge_ok + run: echo 'merge_ok=true' >> ${GITHUB_OUTPUT} + + merge_ok: + name: Merge OK + if: always() + needs: + - set_merge_ok + runs-on: ubuntu-latest + steps: + - run: | + merge_ok="${{ needs.set_merge_ok.outputs.merge_ok }}" + if [[ "${merge_ok}" == "true" ]]; then + echo "Merge OK" + exit 0 + else + echo "Merge NOT OK" + exit 1 + fi diff --git a/Makefile b/Makefile deleted file mode 100644 index 7bb8863..0000000 --- a/Makefile +++ /dev/null @@ -1,60 +0,0 @@ -ROOT_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) -VIRTUALENV_DIR ?= $(ROOT_DIR)/virtualenv - -.PHONY: all -all: requirements virtualenv tox - -.PHONY: clean -clean: .clean-virtualenv - -# list all makefile targets -.PHONY: .list -.list: - @$(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | sort | egrep -v -e '^[^[:alnum:]]' -e '^$@$$' | xargs - -.PHONY: requirements -requirements: virtualenv - @echo - @echo "==================== requirements ====================" - @echo - @echo "Start Time = `date --iso-8601=ns`" - . $(VIRTUALENV_DIR)/bin/activate; \ - $(VIRTUALENV_DIR)/bin/pip install --cache-dir $(HOME)/.pip-cache --upgrade pip; \ - $(VIRTUALENV_DIR)/bin/pip install --cache-dir $(HOME)/.pip-cache -q -r $(ROOT_DIR)/requirements.txt; \ - $(VIRTUALENV_DIR)/bin/pip install --cache-dir $(HOME)/.pip-cache -q -r $(ROOT_DIR)/test-requirements.txt; - @echo "End Time = `date --iso-8601=ns`" - -.PHONY: virtualenv -virtualenv: $(VIRTUALENV_DIR)/bin/activate -$(VIRTUALENV_DIR)/bin/activate: - @echo - @echo "==================== virtualenv ====================" - @echo - @echo "Start Time = `date --iso-8601=ns`" - if [ ! -d "$(VIRTUALENV_DIR)" ]; then \ - if [ -d "$(ROOT_VIRTUALENV)" ]; then \ - $(ROOT_DIR)/bin/clonevirtualenv.py $(ROOT_VIRTUALENV) $(VIRTUALENV_DIR);\ - else \ - virtualenv --no-site-packages $(VIRTUALENV_DIR);\ - fi; \ - fi; - @echo "End Time = `date --iso-8601=ns`" - -.PHONY: .clean-virtualenv -.clean-virtualenv: - @echo - @echo "==================== cleaning virtualenv ====================" - @echo - @echo "Start Time = `date --iso-8601=ns`" - rm -rf $(VIRTUALENV_DIR) - @echo "End Time = `date --iso-8601=ns`" - -.PHONY: tox -tox: requirements - @echo - @echo "==================== tox ====================" - @echo - @echo "Start Time = `date --iso-8601=ns`" - . $(VIRTUALENV_DIR)/bin/activate; \ - $(VIRTUALENV_DIR)/bin/tox - @echo "End Time = `date --iso-8601=ns`" diff --git a/README.md b/README.md index 9269df6..bbab5a6 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,6 @@ # HashiCorp Vault authentication backend for StackStorm -[![Build Status](https://github.com/StackStorm/st2-auth-backend-vault/actions/workflows/ci.yaml/badge.svg)](https://github.com/StackStorm/st2-auth-backend-vault/actions/workflows/ci.yaml) -[![Join our community Slack](https://stackstorm-community.herokuapp.com/badge.svg)](https://stackstorm.com/community-signup) -[![Forum](https://img.shields.io/discourse/https/forum.stackstorm.com/posts.svg)](https://forum.stackstorm.com/) +[![Build Status](https://github.com/StackStorm/st2-auth-backend-vault/actions/workflows/tox.yaml/badge.svg)](https://github.com/StackStorm/st2-auth-backend-vault/actions/workflows/tox.yaml) ## Overview diff --git a/Vagrantfile b/Vagrantfile deleted file mode 100644 index 8a04781..0000000 --- a/Vagrantfile +++ /dev/null @@ -1,19 +0,0 @@ -vault_addr = ENV['VAULT_ADDR'] ? ENV['VAULT_ADDR'] : 'http://127.0.0.1:8200' -vault_token = ENV['VAULT_TOKEN'] ? ENV['VAULT_TOKEN'] : 'st2token' - - -Vagrant.configure("2") do |config| - config.vm.provider "docker" do |d| - d.image = "vault" - # https://hub.docker.com/_/vault/ - d.create_args = ["--cap-add=IPC_LOCK"] - d.env = {"VAULT_DEV_ROOT_TOKEN_ID" => vault_token, - "VAULT_ADDR" => vault_addr} - d.ports = ["127.0.0.1:8200:8200"] - end - - config.vm.provision "docker" do |d| - d.run "vault", - cmd: "vault" - end -end diff --git a/lint-configs/python/.pylintrc b/lint-configs/python/.pylintrc index 8e2d3c5..2ac0894 100644 --- a/lint-configs/python/.pylintrc +++ b/lint-configs/python/.pylintrc @@ -1,14 +1,9 @@ [MESSAGES CONTROL] # C0111 Missing docstring # I0011 Warning locally suppressed using disable-msg -# I0012 Warning locally suppressed using disable-msg -# W0704 Except doesn't do anything Used when an except clause does nothing but "pass" and there is no "else" clause -# W0142 Used * or * magic* Used when a function or method is called using *args or **kwargs to dispatch arguments. # W0212 Access to a protected member %s of a client class -# W0232 Class has no __init__ method Used when a class has no __init__ method, neither its parent classes. # W0613 Unused argument %r Used when a function or method argument is not used. # W0702 No exception's type specified Used when an except clause doesn't specify exceptions type to catch. -# R0201 Method could be a function # W0614 Unused import XYZ from wildcard import # R0914 Too many local variables # R0912 Too many branches @@ -16,7 +11,7 @@ # R0913 Too many arguments # R0904 Too many public methods # E0211: Method has no argument -disable=C0103,C0111,I0011,I0012,W0704,W0142,W0212,W0232,W0613,W0702,R0201,W0614,R0914,R0912,R0915,R0913,R0904,R0801 +disable=C0103,C0111,I0011,W0212,W0613,W0702,W0614,R0914,R0912,R0915,R0913,R0904,R0801 [TYPECHECK] # Note: This modules are manipulated during the runtime so we can't detect all the properties during diff --git a/setup.py b/setup.py index e683263..5d439c5 100644 --- a/setup.py +++ b/setup.py @@ -28,10 +28,15 @@ version = parse_version_string(INIT_FILE) install_reqs, dep_links = fetch_requirements(REQUIREMENTS_FILE) +with open("README.md", "r") as fh: + long_description = fh.read() + setup( name='st2-auth-backend-vault', version=version, description='StackStorm authentication backend which reads credentials from an HashiCorp Vault instance.', + long_description=long_description, + long_description_content_type="text/markdown", author='StackStorm, Inc.', author_email='info@stackstorm.com', url='https://github.com/StackStorm/st2-auth-backend-vault', @@ -42,12 +47,14 @@ 'License :: OSI Approved :: Apache Software License', 'Programming Language :: Python', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', 'Intended Audience :: Developers', 'Environment :: Console', ], + python_requires='>=3.8', platforms=['Any'], scripts=[], provides=['st2auth_vault_backend'], @@ -55,7 +62,6 @@ include_package_data=True, install_requires=install_reqs, dependency_links=dep_links, - test_suite='tests', entry_points={ 'st2auth.backends.backend': [ 'vault = st2auth_vault_backend.vault:VaultAuthenticationBackend', diff --git a/st2auth_vault_backend/__init__.py b/st2auth_vault_backend/__init__.py index cf5545d..5e6689e 100644 --- a/st2auth_vault_backend/__init__.py +++ b/st2auth_vault_backend/__init__.py @@ -19,4 +19,4 @@ 'VaultAuthenticationBackend' ] -__version__ = '0.2.0' +__version__ = '0.3.0' diff --git a/st2auth_vault_backend/vault.py b/st2auth_vault_backend/vault.py index 628f554..74fc09d 100644 --- a/st2auth_vault_backend/vault.py +++ b/st2auth_vault_backend/vault.py @@ -16,7 +16,7 @@ import logging import hvac -from six.moves.urllib.parse import urlparse +from urllib.parse import urlparse __all__ = [ "VaultAuthenticationBackend" diff --git a/test-requirements.txt b/test-requirements.txt index 37f392f..6dc129d 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -1,14 +1,8 @@ -astroid==1.6.5 -# fix isort dependency of pylint 1.9.4 by keeping it below its 5.x version -isort>=4.2.5,<5 -mock==3.0.5 -nose-timer==0.7.5 -nose>=1.3.7 +flake8==7.0.0 +mock==5.1.0 pep8==1.7.1 pylint-plugin-utils>=0.4 -pylint==1.9.4 -rednose -st2flake8==0.1.0 -flake8<5 # st2flake8 does not support flake8 5 -tox==3.14.1 -unittest2 +pylint~=3.1.0 +pytest +st2flake8 +tox diff --git a/tests/unit/test_vault_backend.py b/tests/unit/test_vault_backend.py index fee82af..3a27b5f 100644 --- a/tests/unit/test_vault_backend.py +++ b/tests/unit/test_vault_backend.py @@ -14,12 +14,12 @@ # limitations under the License. import sys - import unittest +import http.client +from urllib.parse import urlparse + import mock from requests.models import Response -from six.moves import http_client -from six.moves.urllib.parse import urlparse from st2auth_vault_backend.vault import VaultAuthenticationBackend @@ -43,8 +43,8 @@ def _mock_vault_request(*args, **kwargs): def _mock_vault_login(*args, **kwargs): return_codes = { - "good": http_client.OK, - "bad": http_client.BAD_REQUEST, + "good": http.client.OK, + "bad": http.client.BAD_REQUEST, } return_json = { "good": b'{"auth": {"client_token": "good_token"}}', @@ -92,14 +92,14 @@ def _mock_vault_login(*args, **kwargs): def _mock_vault_token_lookup_self(*args, **kwargs): return_codes = { - "good_token": http_client.OK, + "good_token": http.client.OK, } return_json = { "good_token": b'{"auth": {"client_token": "good_token"}}', } headers = kwargs.get('headers') - code = http_client.BAD_REQUEST + code = http.client.BAD_REQUEST return_content = '{}' if return_codes.get(headers['X-Vault-Token']): code = return_codes[headers['X-Vault-Token']] @@ -114,7 +114,7 @@ def _mock_vault_token_lookup_self(*args, **kwargs): def _mock_vault_token_lookup(*args, **kwargs): return_codes = { - "good_token": http_client.OK, + "good_token": http.client.OK, } return_json = { "good_token": b'{"auth": {"client_token": "good_token"}}', @@ -122,7 +122,7 @@ def _mock_vault_token_lookup(*args, **kwargs): body = kwargs.get("json") headers = kwargs.get('headers') - code = http_client.BAD_REQUEST + code = http.client.BAD_REQUEST return_content = '{}' if return_codes.get(body['token']): code = return_codes[body['token']] @@ -453,4 +453,4 @@ def test_authenticate_userpass(self, okta): self.assertFalse(backend.authenticate("bad", "password")) if __name__ == "__main__": - sys.exit(unittest2.main()) + sys.exit(unittest.main()) diff --git a/tox.ini b/tox.ini index 13e2de2..597371c 100644 --- a/tox.ini +++ b/tox.ini @@ -1,15 +1,16 @@ [tox] -envlist = py27,py36,lint,integration +envlist = py{38,39,310,311}-{unit,integration},lint +# tox parses py* in the env name to set base python [testenv] deps = -r{toxinidir}/test-requirements.txt -commands = nosetests -s -v --rednose --with-timer tests/unit/ + +[testenv:py{38,39,310,311}-unit] +commands = pytest tests/unit/ + +[testenv:py{38,39,310,311}-integration] +commands = pytest tests/integration/ [testenv:lint] -deps = -r{toxinidir}/test-requirements.txt commands = flake8 --config ./lint-configs/python/.flake8 st2auth_vault_backend/ pylint -E --rcfile=./lint-configs/python/.pylintrc st2auth_vault_backend/ - -[testenv:integration] -deps = -r{toxinidir}/test-requirements.txt -commands = nosetests -s -v --rednose --with-timer tests/integration/