mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-09 20:26:33 +00:00
Merge branch 'feature/ai-agent-employees' into feature/store-i18n
This commit is contained in:
170 files changed
+4745
-566
No files matched your search
@@ -90,9 +90,19 @@ class TestApiLookup(unittest.TestCase):
|
||||
self.lookup.run(["cloudflare.api_token"], variables={"API": "nope"})
|
||||
self.assertIn("mapping", str(ctx.exception))
|
||||
|
||||
def test_missing_api_global_raises_unknown_key(self):
|
||||
def test_missing_api_global_falls_back_to_the_declaration(self):
|
||||
self.assertEqual(self.lookup.run(["cloudflare.api_token"], variables={})[0], "")
|
||||
|
||||
def test_a_provider_the_scope_omits_still_resolves(self):
|
||||
out = self.lookup.run(
|
||||
["github.client_id"],
|
||||
variables={"API": {"cloudflare": {"api_token": "cf"}}},
|
||||
)
|
||||
self.assertEqual(out, [""])
|
||||
|
||||
def test_an_undeclared_provider_still_raises(self):
|
||||
with self.assertRaises(AnsibleError):
|
||||
self.lookup.run(["cloudflare.api_token"], variables={})
|
||||
self.lookup.run(["nope.api_key"], variables=self.vars)
|
||||
|
||||
def test_templar_resolves_jinja_values(self):
|
||||
self.lookup._templar = _FakeTemplar(mapping={"{{ vault_cf }}": "secret-cf"})
|
||||
|
||||
@@ -119,5 +119,133 @@ class TestContainerPortsLookup(unittest.TestCase):
|
||||
self.assertEqual(out, ['ports:\n - "10.0.0.1:8002:3000"'])
|
||||
|
||||
|
||||
def _edge_apps():
|
||||
return {
|
||||
"web-svc-coturn": {
|
||||
"services": {
|
||||
"coturn": {
|
||||
"ports": {
|
||||
"public": {
|
||||
"stun_turn": 3481,
|
||||
"relay": {"start": 20000, "end": 39999},
|
||||
}
|
||||
}
|
||||
},
|
||||
"openresty": {
|
||||
"ports": {
|
||||
"internal": {"http": 80},
|
||||
"public": {"http": 80},
|
||||
}
|
||||
},
|
||||
"api": {"ports": {"internal": {"http": 5000}}},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def _run_edge(terms):
|
||||
lookup = LookupModule()
|
||||
lookup._loader = mock.MagicMock()
|
||||
apps = _edge_apps()
|
||||
with patch("plugins.lookup.container_ports.lookup_loader") as loader_mock:
|
||||
loader_mock.get.return_value = mock.MagicMock(run=lambda *_a, **_k: [apps])
|
||||
return lookup.run(terms, variables={"application_id": "web-svc-coturn"})[0]
|
||||
|
||||
|
||||
class TestContainerPortsDictTerms(unittest.TestCase):
|
||||
def test_one_list_item_per_transport(self):
|
||||
out = _run_edge(
|
||||
[
|
||||
{
|
||||
"service": "coturn",
|
||||
"protocol": "stun_turn",
|
||||
"transport": ["udp", "tcp"],
|
||||
"container": "same",
|
||||
}
|
||||
]
|
||||
)
|
||||
self.assertEqual(out, 'ports:\n - "3481:3481/udp"\n - "3481:3481/tcp"')
|
||||
|
||||
def test_a_range_renders_on_both_sides(self):
|
||||
out = _run_edge(
|
||||
[
|
||||
{
|
||||
"service": "coturn",
|
||||
"protocol": "relay",
|
||||
"transport": "udp",
|
||||
"container": "same",
|
||||
}
|
||||
]
|
||||
)
|
||||
self.assertEqual(out, 'ports:\n - "20000-39999:20000-39999/udp"')
|
||||
|
||||
def test_host_mode_emits_the_long_block(self):
|
||||
out = _run_edge([{"service": "openresty", "protocol": "http", "mode": "host"}])
|
||||
self.assertEqual(
|
||||
out,
|
||||
"ports:\n - target: 80\n published: 80\n"
|
||||
" protocol: tcp\n mode: host",
|
||||
)
|
||||
|
||||
def test_ephemeral_publishes_only_the_container_port(self):
|
||||
out = _run_edge(
|
||||
[{"service": "api", "protocol": "http", "publish": "ephemeral"}]
|
||||
)
|
||||
self.assertEqual(out, 'ports:\n - "5000"')
|
||||
|
||||
def test_host_mode_rejects_an_ip(self):
|
||||
with self.assertRaises(AnsibleError):
|
||||
_run_edge(
|
||||
[
|
||||
{
|
||||
"service": "openresty",
|
||||
"protocol": "http",
|
||||
"mode": "host",
|
||||
"ip": "10.0.0.1",
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
def test_an_unknown_term_key_is_rejected(self):
|
||||
with self.assertRaises(AnsibleError):
|
||||
_run_edge([{"service": "openresty", "protocol": "http", "protokol": "tcp"}])
|
||||
|
||||
def test_key_names_the_block(self):
|
||||
lookup = LookupModule()
|
||||
lookup._loader = mock.MagicMock()
|
||||
with patch("plugins.lookup.container_ports.lookup_loader") as loader_mock:
|
||||
loader_mock.get.return_value = mock.MagicMock(
|
||||
run=lambda *_a, **_k: [_edge_apps()]
|
||||
)
|
||||
out = lookup.run(
|
||||
[["openresty", "http"]],
|
||||
variables={"application_id": "web-svc-coturn"},
|
||||
key="expose",
|
||||
)
|
||||
self.assertEqual(out, ['expose:\n - "80:80"'])
|
||||
|
||||
def test_an_unknown_block_key_is_rejected(self):
|
||||
lookup = LookupModule()
|
||||
lookup._loader = mock.MagicMock()
|
||||
with (
|
||||
patch("plugins.lookup.container_ports.lookup_loader") as loader_mock,
|
||||
self.assertRaises(AnsibleError),
|
||||
):
|
||||
loader_mock.get.return_value = mock.MagicMock(
|
||||
run=lambda *_a, **_k: [_edge_apps()]
|
||||
)
|
||||
lookup.run(
|
||||
[["openresty", "http"]],
|
||||
variables={"application_id": "web-svc-coturn"},
|
||||
key="publish",
|
||||
)
|
||||
|
||||
def test_an_unknown_transport_is_rejected(self):
|
||||
with self.assertRaises(AnsibleError):
|
||||
_run_edge(
|
||||
[{"service": "openresty", "protocol": "http", "transport": "sctp"}]
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -66,9 +66,28 @@ class OidcFlavorLookupTests(unittest.TestCase):
|
||||
self._patcher = mock.patch.object(self.mod, "lookup_loader")
|
||||
self._loader_mock = self._patcher.start()
|
||||
self._stub_payload = None
|
||||
self._loader_mock.get.return_value = mock.MagicMock(
|
||||
run=lambda *_a, **_k: [self._stub_payload]
|
||||
)
|
||||
self._loader_mock.get.side_effect = self._stub_lookup
|
||||
|
||||
def _stub_lookup(self, name, *_args, **_kwargs):
|
||||
"""Stand in for the lookups the plugin consumes.
|
||||
|
||||
``config`` resolves a dotted path against the payload the way
|
||||
``lookup('config', app, path, default)`` does with a default supplied;
|
||||
anything else answers with the payload itself.
|
||||
"""
|
||||
if name == "config":
|
||||
return mock.MagicMock(
|
||||
run=lambda terms, **_kw: [self._stub_config(*terms)],
|
||||
)
|
||||
return mock.MagicMock(run=lambda *_a, **_kw: [self._stub_payload])
|
||||
|
||||
def _stub_config(self, application_id, config_path, default=None):
|
||||
node = (self._stub_payload or {}).get(application_id)
|
||||
for part in str(config_path).split("."):
|
||||
if not isinstance(node, dict) or part not in node:
|
||||
return default
|
||||
node = node[part]
|
||||
return node
|
||||
|
||||
def tearDown(self):
|
||||
self._patcher.stop()
|
||||
|
||||
@@ -9,7 +9,7 @@ from ansible.errors import AnsibleError
|
||||
from plugins.lookup.tor_ports import (
|
||||
LookupModule,
|
||||
collect_exposed_ports,
|
||||
collect_public_ports,
|
||||
collect_onion_ports,
|
||||
)
|
||||
from utils.cache import _reset_cache_for_tests
|
||||
from utils.cache.yaml import dump_yaml_str
|
||||
@@ -33,7 +33,15 @@ class TestTorPortsLookup(unittest.TestCase):
|
||||
_write_services(
|
||||
self.roles_dir,
|
||||
"web-app-gitea",
|
||||
{"gitea": {"ports": {"public": {"ssh": 2201}, "local": {"http": 8002}}}},
|
||||
{
|
||||
"gitea": {
|
||||
"ports": {
|
||||
"public": {"ssh": 2201},
|
||||
"local": {"http": 8002},
|
||||
"onion": {"ssh": True},
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
_write_services(
|
||||
self.roles_dir,
|
||||
@@ -68,40 +76,159 @@ class TestTorPortsLookup(unittest.TestCase):
|
||||
_reset_cache_for_tests()
|
||||
self._tmpdir.cleanup()
|
||||
|
||||
def test_collects_public_single_ints_sorted(self) -> None:
|
||||
ports = collect_public_ports(
|
||||
["web-app-gitea", "svc-db-openldap"], self.roles_dir
|
||||
@staticmethod
|
||||
def _apps(**roles: dict) -> dict:
|
||||
"""The variant-merged applications view for the given roles.
|
||||
|
||||
Every entity keeps its own ``ports``; the top-level ``tor:`` block of
|
||||
``meta/services.yml`` merges in as one more entity alongside them.
|
||||
"""
|
||||
return {role: {"services": dict(entities)} for role, entities in roles.items()}
|
||||
|
||||
def test_only_named_categories_are_forwarded_sorted(self) -> None:
|
||||
apps = self._apps(
|
||||
**{
|
||||
"web-app-gitea": {
|
||||
"gitea": {
|
||||
"ports": {"public": {"ssh": 2201}, "onion": {"ssh": True}}
|
||||
}
|
||||
},
|
||||
"web-app-mailu": {
|
||||
"mailu": {
|
||||
"ports": {
|
||||
"public": {"smtp": 25, "smtps": 465, "imap": 143},
|
||||
"onion": {"smtp": True},
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
||||
self.assertEqual(ports, [636, 2201])
|
||||
|
||||
def test_relay_ranges_excluded(self) -> None:
|
||||
ports = collect_public_ports(["web-svc-coturn"], self.roles_dir)
|
||||
self.assertEqual(ports, [3481, 5351])
|
||||
ports = collect_onion_ports(apps, ["web-app-gitea", "web-app-mailu"])
|
||||
|
||||
def test_media_category_excluded(self) -> None:
|
||||
_write_services(
|
||||
self.roles_dir,
|
||||
"web-app-jitsi",
|
||||
{"jitsi": {"ports": {"public": {"media": 10000}, "local": {"http": 8084}}}},
|
||||
self.assertEqual(ports, [25, 2201])
|
||||
|
||||
def test_local_wins_over_public_for_the_same_category(self) -> None:
|
||||
"""``container_ports`` publishes the local port when the category has
|
||||
one, so the forward must target that and not the public alias."""
|
||||
apps = self._apps(
|
||||
**{
|
||||
"web-app-x": {
|
||||
"x": {
|
||||
"ports": {
|
||||
"local": {"http": 8080},
|
||||
"public": {"http": 80},
|
||||
"onion": {"http": True},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
self.assertEqual(collect_public_ports(["web-app-jitsi"], self.roles_dir), [])
|
||||
|
||||
def test_roles_without_public_ports_yield_nothing(self) -> None:
|
||||
self.assertEqual(collect_public_ports(["web-app-hugo"], self.roles_dir), [])
|
||||
self.assertEqual(collect_onion_ports(apps, ["web-app-x"]), [8080])
|
||||
|
||||
def test_tor_disabled_role_excluded(self) -> None:
|
||||
_write_services(
|
||||
self.roles_dir,
|
||||
"web-app-optout",
|
||||
{
|
||||
"optout": {"ports": {"public": {"ssh": 2299}}},
|
||||
"tor": {"enabled": False},
|
||||
},
|
||||
def test_a_falsy_or_unrendered_flag_forwards_nothing(self) -> None:
|
||||
"""The input must be the rendered view: template text left in the flag
|
||||
is not quietly read as enabled."""
|
||||
apps = self._apps(
|
||||
**{
|
||||
"web-app-a": {
|
||||
"a": {"ports": {"public": {"ssh": 22}, "onion": {"ssh": False}}}
|
||||
},
|
||||
"web-app-b": {
|
||||
"b": {
|
||||
"ports": {
|
||||
"public": {"ssh": 23},
|
||||
"onion": {"ssh": "{{ 'svc-net-tor' in group_names }}"},
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
||||
self.assertEqual(collect_public_ports(["web-app-optout"], self.roles_dir), [])
|
||||
|
||||
def test_unknown_role_ignored(self) -> None:
|
||||
self.assertEqual(collect_public_ports(["web-app-nope"], self.roles_dir), [])
|
||||
self.assertEqual(collect_onion_ports(apps, ["web-app-a", "web-app-b"]), [])
|
||||
|
||||
def test_udp_only_categories_are_never_forwarded(self) -> None:
|
||||
apps = self._apps(
|
||||
**{
|
||||
"web-svc-coturn": {
|
||||
"coturn": {
|
||||
"ports": {
|
||||
"public": {
|
||||
"media": 10000,
|
||||
"stun_turn": 3481,
|
||||
"stun_turn_tls": 5351,
|
||||
"ssh": 2299,
|
||||
"relay": {"start": 20000, "end": 39999},
|
||||
},
|
||||
"onion": {
|
||||
"media": True,
|
||||
"relay": True,
|
||||
"stun_turn": True,
|
||||
"stun_turn_tls": True,
|
||||
"ssh": True,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
self.assertEqual(collect_onion_ports(apps, ["web-svc-coturn"]), [2299])
|
||||
|
||||
def test_a_category_with_no_declared_port_is_skipped(self) -> None:
|
||||
apps = self._apps(
|
||||
**{
|
||||
"web-app-x": {
|
||||
"x": {"ports": {"public": {"ssh": 2201}, "onion": {"typo": True}}}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
self.assertEqual(collect_onion_ports(apps, ["web-app-x"]), [])
|
||||
|
||||
def test_a_role_without_an_onion_block_forwards_nothing(self) -> None:
|
||||
apps = self._apps(
|
||||
**{"web-app-hugo": {"hugo": {"ports": {"local": {"http": 8008}}}}}
|
||||
)
|
||||
|
||||
self.assertEqual(collect_onion_ports(apps, ["web-app-hugo"]), [])
|
||||
|
||||
def test_the_port_flag_is_the_gate_not_the_tor_flag(self) -> None:
|
||||
"""``services.tor.enabled`` is the dependency edge onto svc-net-tor, not
|
||||
the port forward; ``ports.onion`` alone decides what gets a
|
||||
HiddenServicePort."""
|
||||
apps = self._apps(
|
||||
**{
|
||||
"web-app-gitea": {
|
||||
"tor": {"enabled": False},
|
||||
"gitea": {
|
||||
"ports": {"public": {"ssh": 2201}, "onion": {"ssh": True}}
|
||||
},
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
self.assertEqual(collect_onion_ports(apps, ["web-app-gitea"]), [2201])
|
||||
|
||||
def test_role_outside_the_deploy_is_ignored(self) -> None:
|
||||
apps = self._apps(
|
||||
**{
|
||||
"web-app-gitea": {
|
||||
"gitea": {
|
||||
"ports": {"public": {"ssh": 2201}, "onion": {"ssh": True}}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
self.assertEqual(collect_onion_ports(apps, ["web-app-nope"]), [])
|
||||
|
||||
def test_collect_onion_ports_ignores_non_mappings(self) -> None:
|
||||
self.assertEqual(collect_onion_ports({}, ["a"]), [])
|
||||
self.assertEqual(collect_onion_ports(None, ["a"]), [])
|
||||
apps = {"a": {"services": {"s": {"ports": {"onion": True}}}}}
|
||||
self.assertEqual(collect_onion_ports(apps, ["a"]), [])
|
||||
|
||||
def test_collect_exposed_ports_gated_and_deployed(self) -> None:
|
||||
apps = {
|
||||
@@ -151,6 +278,14 @@ class TestTorPortsLookup(unittest.TestCase):
|
||||
)[0]
|
||||
self.assertEqual(result, [{"onion_port": 2201, "target": "127.0.0.1:2201"}])
|
||||
|
||||
def test_run_forwards_nothing_without_an_onion_opt_in(self) -> None:
|
||||
result = self.lookup.run(
|
||||
[],
|
||||
variables={"group_names": ["svc-db-openldap", "web-svc-coturn"]},
|
||||
roles_dir=str(self.roles_dir),
|
||||
)[0]
|
||||
self.assertEqual(result, [])
|
||||
|
||||
def test_empty_group_names(self) -> None:
|
||||
result = self.lookup.run([], variables={}, roles_dir=str(self.roles_dir))[0]
|
||||
self.assertEqual(result, [])
|
||||
|
||||
Reference in new issue
Block a user