feat(syslog): set-up help on the page, port 5514 published, Docker-hidden senders called out (#6003)
CI / lint (push) Successful in 2s
CI / unit (push) Successful in 1m29s
CI / integration (push) Successful in 1m38s
CI / publish (push) Successful in 20s

The Syslog page says where to send (this server, its port and protocols) and
where the setting is on Synology, QNAP, TrueNAS, OpenWrt, UniFi and rsyslog,
open until a device sends. A sender whose address is on Steward's own
container network (Swarm ingress publishing hides the real sender) is
flagged, with the host-mode ports to publish instead. compose files and the
Dockerfile publish 5514/udp and /tcp; docs/plugins/syslog.md describes the
plugin and the deploy.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-19 07:01:56 -04:00
co-authored by Claude Opus 5.5
parent 96f774ce24
commit ed9da56efa
10 changed files with 221 additions and 5 deletions
+27
View File
@@ -0,0 +1,27 @@
"""Whether a sender's address is Docker's (#6003): the container's own
networks read from /proc/net/route."""
import ipaddress
from plugins.syslog.network import on_own_network, subnets_from
# A swarm task on the ingress network (10.0.0.0/24) and an overlay (10.0.5.0/24),
# with its default route through the bridge gateway 172.18.0.1.
ROUTE = """Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
eth1 00000000 010012AC 0003 0 0 0 00000000 0 0 0
eth0 0000000A 00000000 0001 0 0 0 00FFFFFF 0 0 0
eth2 0005000A 00000000 0001 0 0 0 00FFFFFF 0 0 0
eth1 000012AC 00000000 0001 0 0 0 0000FFFF 0 0 0
eth9 nonsense
"""
def test_the_directly_connected_networks_are_read_the_default_route_left_out():
assert subnets_from(ROUTE) == [ipaddress.IPv4Network("10.0.0.0/24"), ipaddress.IPv4Network("10.0.5.0/24"),
ipaddress.IPv4Network("172.18.0.0/16")]
def test_a_sender_on_a_container_network_is_flagged_and_a_lan_one_is_not():
nets = subnets_from(ROUTE)
assert on_own_network("10.0.0.2", nets) and on_own_network("172.18.0.1", nets)
assert not on_own_network("192.168.1.20", nets)
assert not on_own_network("not an address", nets) and not on_own_network("10.0.0.2", [])
+18 -1
View File
@@ -27,7 +27,7 @@ async def _render(app, role, **ctx):
from quart import session
ctx = {"listener": _listener(), "sources": [], "offered": [], "ignored": [],
"hosts": [NS(id="h1", name="SynNAS", address="192.168.0.7")],
"now": datetime.now(timezone.utc), **ctx}
"server": "steward.lan", "now": datetime.now(timezone.utc), **ctx}
async with app.test_request_context("/plugins/syslog/"):
session["user_role"] = role
page = await render_plugin_template(app, "syslog", "syslog/index.html", **ctx)
@@ -62,6 +62,23 @@ async def test_a_port_it_cannot_open_is_said(app):
assert "No sources yet." in page
async def test_setup_help_names_this_server_and_opens_until_a_device_sends(app):
page = await _render(app, "viewer")
assert '<details class="card" id="syslog-setup" open>' in page
assert "send to <span class=\"mono\">steward.lan</span>, port <span class=\"mono\">5514</span>, UDP or TCP" in page
assert "*.* @@steward.lan:5514" in page and "mode: host" in page
added = await _render(app, "viewer", sources=[_source("SynNAS", "accepted")])
assert '<details class="card" id="syslog-setup">' in added # closed once one sends
async def test_a_sender_on_dockers_own_network_is_called_out(app):
hidden = {**_source("ingress", "offered"), "address": "10.0.0.2", "docker_address": True}
page = await _render(app, "admin", offered=[hidden, {**hidden, "id": "id-2"}])
assert "10.0.0.2 is on Steward's own container network" in page
assert page.count("Docker's address, not the device's") == 2
assert "own container network" not in await _render(app, "admin", offered=[_source("synnas", "offered")])
async def test_the_edit_page_has_its_trail_and_a_remove(app):
from quart import session
source = NS(id="s1", name="SynNAS", hostname_seen="synnas", address="192.168.0.7", host_id=None)