Increase code coverage of utils/encrypt.py (#86060)

* Add encryption code coverage

Co-authored-by: Matt Clay <matt@mystile.com>
This commit is contained in:
David Shrewsbury
2025-11-06 15:26:41 -05:00
committed by GitHub
parent a4ae978122
commit e3cff24134
2 changed files with 110 additions and 0 deletions

View File

@@ -87,3 +87,53 @@
assert:
that:
- yescrypt_hash_salt == '$y$j9T$V7qMYJaNbVKOeh4PhtqPk/$x7rTqZ.RpI07.dkBSxcg.jLM8ODUfx25rCN0cFsAUg0'
- name: Test salt with invalid character
set_fact:
md5_hash: "{{ 'test' | password_hash('md5_crypt', salt='123^') }}"
ignore_errors: yes
register: bad_salt_result
- name: Determine if bad salt character was recognized
assert:
that: bad_salt_result.msg is contains 'invalid characters in salt'
- name: Test supplying invalid salt size with algo needing exact size
set_fact:
bcrypt_hash: "{{ 'test' | password_hash('bcrypt', salt='12345', salt_size=5) }}"
ignore_errors: yes
register: bad_salt_result
- name: Determine if salt size mismatch caught
assert:
that: bad_salt_result.msg is contains 'invalid salt size supplied (5), expected 22'
- name: Test salt with exact size mismatch
set_fact:
bcrypt_hash: "{{ 'test' | password_hash('bcrypt', salt='123') }}"
ignore_errors: yes
register: bad_salt_result
- name: Determine if salt size mismatch caught
assert:
that: bad_salt_result.msg is contains 'invalid salt size supplied (3), expected 22'
- name: Test supplying too big salt
set_fact:
bcrypt_hash: "{{ 'test' | password_hash('md5_crypt', salt='1234567890') }}"
ignore_errors: yes
register: bad_salt_result
- name: Determine if too big salt caught
assert:
that: bad_salt_result.msg is contains 'invalid salt size supplied (10), expected at most 8'
- name: Test supplying too big salt size
set_fact:
bcrypt_hash: "{{ 'test' | password_hash('md5_crypt', salt='1234567890', salt_size=10) }}"
ignore_errors: yes
register: bad_salt_result
- name: Determine if too big salt size caught
assert:
that: bad_salt_result.msg is contains 'invalid salt size supplied (10), expected at most 8'

View File

@@ -7,6 +7,8 @@ import warnings
import pytest
from pytest_mock import MockerFixture
from ansible.errors import AnsibleError
from ansible.plugins.filter.core import get_encrypted_password
@@ -249,3 +251,61 @@ def test_passlib_bcrypt_salt(recwarn):
result = passlib_obj.hash(secret, salt=repaired_salt, ident=ident)
assert result == expected
def test_do_encrypt_no_lib(mocker: MockerFixture) -> None:
"""Test AnsibleError is raised when no encryption library is installed."""
mocker.patch('ansible.utils.encrypt.HAS_CRYPT', False)
mocker.patch('ansible.utils.encrypt.PASSLIB_AVAILABLE', False)
with pytest.raises(AnsibleError, match=r"Unable to encrypt nor hash, either libxcrypt \(recommended\), crypt, or passlib must be installed\."):
encrypt.do_encrypt("123", "sha256_crypt", salt="12345678")
class TestCryptHash:
"""
Tests for the CryptHash class.
These tests are hitting code paths that are otherwise impossible to reach
through integration tests, but necessary for more complete code coverage.
"""
def test_invalid_instantiation(self, mocker: MockerFixture) -> None:
"""Should not be able to instantiate a CryptHash class without libxcrypt/libcrypt."""
mocker.patch('ansible.utils.encrypt.HAS_CRYPT', False)
with pytest.raises(AnsibleError, match=r"crypt cannot be used as the 'libxcrypt' library is not installed or is unusable\."):
encrypt.CryptHash("sha256_crypt")
def test_ansible_unsupported_algorithm(self) -> None:
"""Test AnsibleError is raised when Ansible does not support requested algorithm."""
with pytest.raises(AnsibleError, match=r"crypt does not support 'foo' algorithm"):
encrypt.CryptHash("foo")
def test_library_unsupported_algorithm(self, mocker: MockerFixture) -> None:
"""Test AnsibleError is raised when crypt library does not support an Ansible supported algorithm."""
# Pretend we have a crypt lib that doesn't like our algo
mocker.patch('ansible.utils.encrypt.HAS_CRYPT', True)
mocker.patch('ansible._internal._encryption._crypt.crypt', side_effect=ValueError)
# instantiate with an Ansible supported algo
crypt_hash = encrypt.CryptHash("sha256_crypt")
with pytest.raises(AnsibleError, match=r"crypt does not support 'sha256_crypt' algorithm"):
crypt_hash.hash("123", salt="12345678")
class TestPasslibHash:
"""
Tests for the PasslibHash class.
These tests are hitting code paths that are otherwise impossible to reach
through integration tests, but necessary for more complete code coverage.
"""
def test_invalid_instantiation(self, mocker: MockerFixture) -> None:
"""Should not be able to instantiate a PasslibHash class without passlib."""
mocker.patch('ansible.utils.encrypt.PASSLIB_AVAILABLE', False)
with pytest.raises(AnsibleError, match=r"The passlib Python package must be installed to hash with the 'sha256_crypt' algorithm\."):
encrypt.PasslibHash("sha256_crypt")