firegex/tests/integration/test_external.py
2026-09-13 15:54:56 +02:00

77 lines
3.5 KiB
Python

"""The hand-off: firegex steers traffic into a proxy the operator wrote, and runs nothing.
Note the shape of these tests. Linux refuses a loopback connection to a port with no
listener *without emitting a packet*, so no rule can rescue it — a hand-off test has to
keep the real service listening and tell the two apart by their replies, not by which one
fails to answer. The stand-in proxy answers with a marker; the real service echoes.
"""
import pytest
from integration.conftest import EXTERNAL_MARKER, start_and_settle
from helpers.traffic import reaches
pytestmark = pytest.mark.instance
def test_traffic_aimed_at_the_service_reaches_your_proxy_instead(api, protected,
external_layer):
service_id, server, _ = protected(external_layer, name="ext")
start_and_settle(api, service_id)
assert reaches(server.external, EXTERNAL_MARKER), \
"the traffic reached the real service instead of the operator's proxy"
def test_the_log_records_the_hand_off(api, protected, external_layer):
service_id, _, _ = protected(external_layer, name="extlog")
start_and_settle(api, service_id)
entries = api.services_logs(service_id)
assert any("started on the external layer" in e["text"] for e in entries), \
str(entries[-3:])
def test_attaching_a_filter_to_a_running_hand_off_is_refused_naming_the_reason(
api, protected, external_layer):
"""A filter here would be one that never runs.
No firegex process is in the path — the rules rewrite the destination and change it
back — so a filter attached to this layer is not a slow filter or a weak one, it is a
filter that is never consulted. Refused at the moment it is attached rather than
accepted and broken later.
"""
service_id, _, _ = protected(external_layer, name="extflt")
start_and_settle(api, service_id)
why = api.services_add_filter_error(service_id, "regex", "patterns")
assert why is not None, "a filter was attached to a running hand-off"
assert "would never run" in why, why
def test_a_filter_stored_while_stopped_refuses_the_start_with_the_same_reason(
api, protected, external_layer):
"""Stopped, the service is only configuration, so the filter is stored — and then
starting is what refuses. A row that is created happily and then refuses to start
every time is a trap, so the reason is the same one either way."""
service_id, _, _ = protected(external_layer, name="extstop")
assert api.services_add_filter(service_id, "regex", "patterns")
filter_id = api.services_filters(service_id)[0]["filter_id"]
why = api.services_start_error(service_id)
assert why is not None, "a hand-off with a filter started"
assert "would never run" in why, why
assert api.services_delete_filter(service_id, filter_id)
start_and_settle(api, service_id)
def test_two_addresses_cannot_share_one_proxy_endpoint(api, protected, external_layer):
"""The return rule recognises the operator's proxy by address and port to put the
original port back, so two addresses behind one endpoint could not be told apart on
the way out."""
from helpers.net import free_port
service_id, server, _ = protected(external_layer, name="extdup")
why = api.services_add_address_error(
service_id, external_layer.ip, free_port(external_layer.ipv6),
proxy_ip=external_layer.ip, proxy_port=server.external.port)
assert why is not None, "two addresses were allowed to share one proxy endpoint"