"""Test CodeNotary.""" from __future__ import annotations from dataclasses import dataclass from unittest.mock import AsyncMock, Mock, patch import pytest from supervisor.exceptions import ( CodeNotaryBackendError, CodeNotaryError, CodeNotaryUntrusted, ) from supervisor.utils.codenotary import calc_checksum, cas_validate pytest.skip("code notary has been disabled due to issues", allow_module_level=True) @dataclass class SubprocessResponse: """Class for specifying subprocess exec response.""" returncode: int = 0 data: str = "" error: str | None = None exception: Exception | None = None @pytest.fixture(name="subprocess_exec") def fixture_subprocess_exec(request): """Mock subprocess exec with specific return.""" response = request.param if response.exception: communicate_return = AsyncMock(side_effect=response.exception) else: communicate_return = AsyncMock(return_value=(response.data, response.error)) exec_return = Mock(returncode=response.returncode, communicate=communicate_return) with patch( "supervisor.utils.codenotary.asyncio.create_subprocess_exec", return_value=exec_return, ) as subprocess_exec: yield subprocess_exec def test_checksum_calc(): """Calc Checkusm as test.""" assert calc_checksum("test") == calc_checksum(b"test") assert ( calc_checksum("test") == "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08" ) async def test_valid_checksum(): """Test a valid autorization.""" await cas_validate( "notary@home-assistant.io", "4434a33ff9c695e870bc5bbe04230ea3361ecf4c129eb06133dd1373975a43f0", ) async def test_invalid_checksum(): """Test a invalid autorization.""" with pytest.raises(CodeNotaryUntrusted): await cas_validate( "notary@home-assistant.io", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", ) @pytest.mark.parametrize( "subprocess_exec", [SubprocessResponse(returncode=1, error=b"x is not notarized")], ) async def test_not_notarized_error(subprocess_exec): """Test received a not notarized error response from command.""" with pytest.raises(CodeNotaryUntrusted): await cas_validate( "notary@home-assistant.io", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", ) @pytest.mark.parametrize( "subprocess_exec", [ SubprocessResponse(returncode=1, error=b"test"), SubprocessResponse(returncode=0, data='{"error":"asn1: structure error"}'), SubprocessResponse(returncode=1, error="test".encode("utf-16")), ], indirect=True, ) async def test_cas_backend_error(subprocess_exec): """Test backend error executing cas command.""" with pytest.raises(CodeNotaryBackendError): await cas_validate( "notary@home-assistant.io", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", ) @pytest.mark.parametrize( "subprocess_exec", [SubprocessResponse(returncode=0, data='{"status":1}')], indirect=True, ) async def test_cas_notarized_untrusted(subprocess_exec): """Test cas found notarized but untrusted content.""" with pytest.raises(CodeNotaryUntrusted): await cas_validate( "notary@home-assistant.io", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", ) @pytest.mark.parametrize( "subprocess_exec", [SubprocessResponse(exception=OSError())], indirect=True ) async def test_cas_exec_os_error(subprocess_exec): """Test os error attempting to execute cas command.""" with pytest.raises(CodeNotaryError): await cas_validate( "notary@home-assistant.io", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", )