diff --git a/.ci/bash_functions b/.ci/bash_functions new file mode 100644 index 00000000..1f9020d7 --- /dev/null +++ b/.ci/bash_functions @@ -0,0 +1,13 @@ +# shellcheck shell=bash + +# Tox environment name -> Python executable name (e.g. py312-m_mtg -> python3.12) +toxenv-python() { + local pattern='^py([23])([0-9]{1,2}).*' + if [[ $1 =~ $pattern ]]; then + echo "python${BASH_REMATCH[1]}.${BASH_REMATCH[2]}" + return + else + echo "${FUNCNAME[0]}: $1: environment name not recognised" >&2 + return 1 + fi +} diff --git a/.ci/show_python_versions b/.ci/show_python_versions new file mode 100755 index 00000000..ac219824 --- /dev/null +++ b/.ci/show_python_versions @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +set -o errexit -o nounset -o pipefail + +INDENT=" " +POSSIBLE_PYTHONS=( + python + python2 + python3 + /usr/bin/python + /usr/bin/python2 + /usr/bin/python3 + # GitHub macOS 12 images: python2.7 is installed, but not on $PATH + /Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7 +) + +for p in "${POSSIBLE_PYTHONS[@]}"; do + echo "$p" + if [[ ${p:0:1} == "/" && -e $p ]]; then + : + elif type "$p" > /dev/null 2>&1; then + type "$p" 2>&1 | sed -e "s/^/${INDENT}type: /" + else + echo "${INDENT}Not present" + echo + continue + fi + + $p -c "import sys; print('${INDENT}version: %d.%d.%d' % sys.version_info[:3])" + # macOS builders lack a realpath command + $p -c "import os.path; print('${INDENT}realpath: %s' % os.path.realpath('$(type -p "$p")'))" + $p -c "import sys; print('${INDENT}sys.executable: %s' % sys.executable)" + echo +done diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 18411b35..c9640ac2 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -29,13 +29,10 @@ jobs: - tox_env: py27-m_ans-ans4 - tox_env: py36-m_ans-ans2.10 - python_version: '3.6' - tox_env: py36-m_ans-ans4 - python_version: '3.6' - tox_env: py27-m_mtg - tox_env: py36-m_mtg - python_version: '3.6' steps: - uses: actions/checkout@v4 @@ -44,90 +41,38 @@ jobs: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Install build deps + - run: .ci/show_python_versions + - name: Install deps + id: install-deps run: | set -o errexit -o nounset -o pipefail - - PYTHON=$(python -c 'import re; print(re.sub(r"^py([23])([0-9]{1,2}).*", r"python\1.\2", "${{ matrix.tox_env }}"))') - - if [[ -z $PYTHON ]]; then - echo 1>&2 "Python interpreter could not be determined" - exit 1 - fi + source .ci/bash_functions + PYTHON="$(toxenv-python '${{ matrix.tox_env }}')" sudo apt-get update if [[ $PYTHON == "python2.7" ]]; then sudo apt install -y python2-dev sshpass virtualenv - elif [[ $PYTHON == "python3.6" ]]; then - sudo apt install -y gcc-10 make libbz2-dev liblzma-dev libreadline-dev libsqlite3-dev libssl-dev sshpass virtualenv zlib1g-dev - curl --fail --silent --show-error --location https://pyenv.run | bash - CC=gcc-10 ~/.pyenv/bin/pyenv install --force 3.6 - else - echo 1>&2 "Python interpreter $PYTHON not available" - exit 1 - fi - - name: Show Python versions - run: | - set -o errexit -o nounset -o pipefail - - # macOS builders lack a realpath command - type python && python -c"import os.path;print(os.path.realpath('$(type -p python)'))" && python --version - type python2 && python2 -c"import os.path;print(os.path.realpath('$(type -p python2)'))" && python2 --version - type python3 && python3 -c"import os.path;print(os.path.realpath('$(type -p python3)'))" && python3 --version - echo - - if [ -e /usr/bin/python ]; then - echo "/usr/bin/python: sys.executable: $(/usr/bin/python -c 'import sys; print(sys.executable)')" - fi - - if [ -e /usr/bin/python2 ]; then - echo "/usr/bin/python2: sys.executable: $(/usr/bin/python2 -c 'import sys; print(sys.executable)')" - fi - - if [ -e /usr/bin/python2.7 ]; then - echo "/usr/bin/python2.7: sys.executable: $(/usr/bin/python2.7 -c 'import sys; print(sys.executable)')" - fi - - name: Install tooling - run: | - set -o errexit -o nounset -o pipefail - - # Tox environment name (e.g. py312-m_mtg) -> Python executable name (e.g. python3.12) - PYTHON=$(python -c 'import re; print(re.sub(r"^py([23])([0-9]{1,2}).*", r"python\1.\2", "${{ matrix.tox_env }}"))') - - if [[ -z $PYTHON ]]; then - echo 1>&2 "Python interpreter could not be determined" - exit 1 - fi - - if [[ $PYTHON == "python2.7" ]]; then curl "https://bootstrap.pypa.io/pip/2.7/get-pip.py" --output "get-pip.py" "$PYTHON" get-pip.py --user --no-python-version-warning # Avoid Python 2.x pip masking system pip rm -f ~/.local/bin/{easy_install,pip,wheel} elif [[ $PYTHON == "python3.6" ]]; then + sudo apt install -y gcc-10 make libbz2-dev liblzma-dev libreadline-dev libsqlite3-dev libssl-dev sshpass virtualenv zlib1g-dev + curl --fail --silent --show-error --location https://pyenv.run | bash + CC=gcc-10 ~/.pyenv/bin/pyenv install --force 3.6 PYTHON="$HOME/.pyenv/versions/3.6.15/bin/python3.6" fi "$PYTHON" -m pip install -r "tests/requirements-tox.txt" + echo "python=$PYTHON" >> $GITHUB_OUTPUT - name: Run tests env: GITHUB_ACTOR: ${{ github.actor }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -o errexit -o nounset -o pipefail - - # Tox environment name (e.g. py312-m_mtg) -> Python executable name (e.g. python3.12) - PYTHON=$(python -c 'import re; print(re.sub(r"^py([23])([0-9]{1,2}).*", r"python\1.\2", "${{ matrix.tox_env }}"))') - - if [[ -z $PYTHON ]]; then - echo 1>&2 "Python interpreter could not be determined" - exit 1 - fi - - if [[ $PYTHON == "python3.6" ]]; then - PYTHON="$HOME/.pyenv/versions/3.6.15/bin/python3.6" - fi + PYTHON="${{ steps.install-deps.outputs.python }}" "$PYTHON" -m tox -e "${{ matrix.tox_env }}" @@ -183,60 +128,26 @@ jobs: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Install build deps + - run: .ci/show_python_versions + - name: Install deps + id: install-deps run: | set -o errexit -o nounset -o pipefail + source .ci/bash_functions + PYTHON="$(toxenv-python '${{ matrix.tox_env }}')" sudo apt-get update sudo apt-get install -y sshpass virtualenv - - name: Show Python versions - run: | - set -o errexit -o nounset -o pipefail - - # macOS builders lack a realpath command - type python && python -c"import os.path;print(os.path.realpath('$(type -p python)'))" && python --version - type python2 && python2 -c"import os.path;print(os.path.realpath('$(type -p python2)'))" && python2 --version - type python3 && python3 -c"import os.path;print(os.path.realpath('$(type -p python3)'))" && python3 --version - echo - - if [ -e /usr/bin/python ]; then - echo "/usr/bin/python: sys.executable: $(/usr/bin/python -c 'import sys; print(sys.executable)')" - fi - - if [ -e /usr/bin/python2 ]; then - echo "/usr/bin/python2: sys.executable: $(/usr/bin/python2 -c 'import sys; print(sys.executable)')" - fi - - if [ -e /usr/bin/python2.7 ]; then - echo "/usr/bin/python2.7: sys.executable: $(/usr/bin/python2.7 -c 'import sys; print(sys.executable)')" - fi - - name: Install tooling - run: | - set -o errexit -o nounset -o pipefail - - # Tox environment name (e.g. py312-m_mtg) -> Python executable name (e.g. python3.12) - PYTHON=$(python -c 'import re; print(re.sub(r"^py([23])([0-9]{1,2}).*", r"python\1.\2", "${{ matrix.tox_env }}"))') - - if [[ -z $PYTHON ]]; then - echo 1>&2 "Python interpreter could not be determined" - exit 1 - fi "$PYTHON" -m pip install -r "tests/requirements-tox.txt" + echo "python=$PYTHON" >> $GITHUB_OUTPUT - name: Run tests env: GITHUB_ACTOR: ${{ github.actor }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -o errexit -o nounset -o pipefail - - # Tox environment name (e.g. py312-m_mtg) -> Python executable name (e.g. python3.12) - PYTHON=$(python -c 'import re; print(re.sub(r"^py([23])([0-9]{1,2}).*", r"python\1.\2", "${{ matrix.tox_env }}"))') - - if [[ -z $PYTHON ]]; then - echo 1>&2 "Python interpreter could not be determined" - exit 1 - fi + PYTHON="${{ steps.install-deps.outputs.python }}" "$PYTHON" -m tox -e "${{ matrix.tox_env }}" @@ -265,61 +176,25 @@ jobs: with: python-version: ${{ matrix.python_version }} if: ${{ matrix.python_version }} - - name: Show Python versions - run: | - set -o errexit -o nounset -o pipefail - - # macOS builders lack a realpath command - type python && python -c"import os.path;print(os.path.realpath('$(type -p python)'))" && python --version - type python2 && python2 -c"import os.path;print(os.path.realpath('$(type -p python2)'))" && python2 --version - type python3 && python3 -c"import os.path;print(os.path.realpath('$(type -p python3)'))" && python3 --version - echo - - if [ -e /usr/bin/python ]; then - echo "/usr/bin/python: sys.executable: $(/usr/bin/python -c 'import sys; print(sys.executable)')" - fi - - if [ -e /usr/bin/python2 ]; then - echo "/usr/bin/python2: sys.executable: $(/usr/bin/python2 -c 'import sys; print(sys.executable)')" - fi - - if [ -e /usr/bin/python2.7 ]; then - echo "/usr/bin/python2.7: sys.executable: $(/usr/bin/python2.7 -c 'import sys; print(sys.executable)')" - fi - - if [ -e /Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7 ]; then - # GitHub macOS 12 images: python2.7 is installed, but not on $PATH - echo "/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7: sys.executable: $(/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7 -c 'import sys; print(sys.executable)')" - fi + - run: .ci/show_python_versions - run: .ci/install_sshpass ${{ matrix.sshpass_version }} if: ${{ matrix.sshpass_version }} - - name: Install tooling + - name: Install deps + id: install-deps run: | set -o errexit -o nounset -o pipefail - - # Tox environment name (e.g. py312-m_mtg) -> Python executable name (e.g. python3.12) - PYTHON=$(python -c 'import re; print(re.sub(r"^py([23])([0-9]{1,2}).*", r"python\1.\2", "${{ matrix.tox_env }}"))') - - if [[ -z $PYTHON ]]; then - echo 1>&2 "Python interpreter could not be determined" - exit 1 - fi + source .ci/bash_functions + PYTHON="$(toxenv-python '${{ matrix.tox_env }}')" "$PYTHON" -m pip install -r "tests/requirements-tox.txt" + echo "python=$PYTHON" >> $GITHUB_OUTPUT - name: Run tests env: GITHUB_ACTOR: ${{ github.actor }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -o errexit -o nounset -o pipefail - - # Tox environment name (e.g. py312-m_mtg) -> Python executable name (e.g. python3.12) - PYTHON=$(python -c 'import re; print(re.sub(r"^py([23])([0-9]{1,2}).*", r"python\1.\2", "${{ matrix.tox_env }}"))') - - if [[ -z $PYTHON ]]; then - echo 1>&2 "Python interpreter could not be determined" - exit 1 - fi + PYTHON="${{ steps.install-deps.outputs.python }}" "$PYTHON" -m tox -e "${{ matrix.tox_env }}" diff --git a/docs/changelog.rst b/docs/changelog.rst index 84f0d77b..7c36f987 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -21,6 +21,9 @@ To avail of fixes in an unreleased version, please download a ZIP file In progress (unreleased) ------------------------ +* :gh:issue:`1329` CI: Refactor and de-duplicate Github Actions workflow +* :gh:issue:`1315` CI: macOS: Increase failed logins limit of test users + v0.3.26 (2025-08-04) -------------------- diff --git a/tests/image_prep/_user_accounts.yml b/tests/image_prep/_user_accounts.yml index bee89084..225d4a53 100644 --- a/tests/image_prep/_user_accounts.yml +++ b/tests/image_prep/_user_accounts.yml @@ -50,7 +50,10 @@ mitogen_test_groups: - name: mitogen__group - name: mitogen__sudo_nopw - tasks: + + user_policies_max_failed_logins: 1000 + user_policies_users: "{{ all_users }}" + pre_tasks: - name: Disable non-localhost SSH for Mitogen users when: false blockinfile: @@ -180,3 +183,5 @@ validate: '/usr/sbin/visudo -cf %s' when: - ansible_virtualization_type != "docker" + roles: + - role: user_policies diff --git a/tests/image_prep/roles/user_policies/defaults/main.yml b/tests/image_prep/roles/user_policies/defaults/main.yml new file mode 100644 index 00000000..f80df944 --- /dev/null +++ b/tests/image_prep/roles/user_policies/defaults/main.yml @@ -0,0 +1,2 @@ +user_policies_max_failed_logins: 10 +user_policies_users: [] diff --git a/tests/image_prep/roles/user_policies/tasks/main.yml b/tests/image_prep/roles/user_policies/tasks/main.yml new file mode 100644 index 00000000..89fff6bc --- /dev/null +++ b/tests/image_prep/roles/user_policies/tasks/main.yml @@ -0,0 +1,11 @@ +- name: Set login attempts (macOS) + vars: + max_failed_logins: "{{ item.policies.max_failed_logins | default(user_policies_max_failed_logins) }}" + command: > + pwpolicy + -u '{{ item.name }}' + -setpolicy 'maxFailedLoginAttempts={{ max_failed_logins }}' + with_items: "{{ user_policies_users }}" + when: + - ansible_system == 'Darwin' + changed_when: true