mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-07 03:15:56 +00:00
A host that defines CAPTCHA with one provider replaces the group_vars mapping (no hash_behaviour merge), so galaxyserver, which configures only hCaptcha, left CAPTCHA.RECAPTCHA undefined. RECAPTCHA_ENABLED then failed to render, the applications render fallback returned the expression as text, and Keycloak's '| bool' coerced it to False with a deprecation warning that ansible-core 2.23 turns into an error. Both flags now check that their provider mapping is defined first; the effective values stay the same for every existing inventory. test_captcha_enabled renders every role's services.recaptcha/hcaptcha.enabled through the real templar for defaults, both providers, only the other provider and only this provider, and fails on the raw text (negative control with the old expression: 4 subtests). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
106 lines
4.1 KiB
Python
106 lines
4.1 KiB
Python
import unittest
|
|
import unittest.mock as mock
|
|
from pathlib import Path
|
|
from typing import Any, ClassVar
|
|
|
|
from ansible.parsing.dataloader import DataLoader
|
|
from ansible.template import Templar
|
|
from ansible.utils.display import Display
|
|
|
|
from utils.cache.base import _render_with_templar
|
|
from utils.cache.files import PROJECT_ROOT
|
|
from utils.cache.yaml import load_yaml_any
|
|
from utils.roles.mapping import ROLE_FILE_META_SERVICES
|
|
|
|
_GENERAL_VARS = Path(PROJECT_ROOT) / "group_vars" / "all" / "00_general.yml"
|
|
_ROLES_DIR = Path(PROJECT_ROOT) / "roles"
|
|
_PROVIDERS = {"recaptcha": "RECAPTCHA", "hcaptcha": "HCAPTCHA"}
|
|
_CREDENTIALS = {"KEY": "site-key", "SECRET": "site-secret"}
|
|
|
|
|
|
def _consumers() -> list[tuple[str, str, str]]:
|
|
found = []
|
|
for role_dir in sorted(_ROLES_DIR.iterdir()):
|
|
services_file = role_dir / ROLE_FILE_META_SERVICES
|
|
if not services_file.is_file():
|
|
continue
|
|
services = load_yaml_any(services_file) or {}
|
|
for service_key, provider in _PROVIDERS.items():
|
|
entry = services.get(service_key)
|
|
enabled = entry.get("enabled") if isinstance(entry, dict) else None
|
|
if isinstance(enabled, str) and f"{provider}_ENABLED" in enabled:
|
|
found.append((role_dir.name, service_key, enabled))
|
|
return found
|
|
|
|
|
|
class TestCaptchaEnabled(unittest.TestCase):
|
|
"""``services.<provider>.enabled`` reaches its consumers through the
|
|
applications render, whose failure path hands back template text instead
|
|
of raising. Inventory ``CAPTCHA`` replaces the group_vars mapping whole,
|
|
so a host that configures one provider drops the other's sub-mapping.
|
|
"""
|
|
|
|
group_vars: ClassVar[dict[str, Any]]
|
|
consumers: ClassVar[list[tuple[str, str, str]]]
|
|
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
cls.group_vars = DataLoader().load_from_file(
|
|
str(_GENERAL_VARS), trusted_as_template=True
|
|
)
|
|
cls.consumers = _consumers()
|
|
|
|
def _render(self, value: str, captcha: dict[str, Any]) -> tuple[Any, list[str]]:
|
|
variables = {**self.group_vars, "CAPTCHA": captcha}
|
|
templar = Templar(loader=DataLoader(), variables=variables)
|
|
with mock.patch.object(Display, "deprecated") as deprecated:
|
|
rendered = _render_with_templar(value, templar=templar, variables=variables)
|
|
coercions = [
|
|
str(call) for call in deprecated.call_args_list if "coerced" in str(call)
|
|
]
|
|
return rendered, coercions
|
|
|
|
def _assert_every_consumer(self, captcha_for, expected_for):
|
|
for role, service_key, value in self.consumers:
|
|
provider = _PROVIDERS[service_key]
|
|
with self.subTest(role=role, service=service_key):
|
|
rendered, coercions = self._render(value, captcha_for(provider))
|
|
self.assertIsInstance(rendered, bool, f"rendered to {rendered!r}")
|
|
self.assertEqual(rendered, expected_for(provider))
|
|
self.assertEqual(coercions, [])
|
|
|
|
def test_every_provider_has_a_consumer(self):
|
|
self.assertEqual(
|
|
{service_key for _, service_key, _ in self.consumers}, set(_PROVIDERS)
|
|
)
|
|
|
|
def test_the_group_vars_defaults_disable_every_provider(self):
|
|
self._assert_every_consumer(
|
|
lambda provider: self.group_vars["CAPTCHA"], lambda provider: False
|
|
)
|
|
|
|
def test_both_credentials_enable_the_provider(self):
|
|
self._assert_every_consumer(
|
|
lambda provider: {name: dict(_CREDENTIALS) for name in _PROVIDERS.values()},
|
|
lambda provider: True,
|
|
)
|
|
|
|
def test_a_host_that_configures_only_the_other_provider_disables_this_one(self):
|
|
def only_the_other(provider):
|
|
return {
|
|
name: dict(_CREDENTIALS)
|
|
for name in _PROVIDERS.values()
|
|
if name != provider
|
|
}
|
|
|
|
self._assert_every_consumer(only_the_other, lambda provider: False)
|
|
|
|
def test_a_host_that_configures_only_this_provider_enables_it(self):
|
|
self._assert_every_consumer(
|
|
lambda provider: {provider: dict(_CREDENTIALS)}, lambda provider: True
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|