push_outputs: is a new sink a channel, a template, or a library? #3173
IsmaelMartinez
started this conversation in
Ideas
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
A small decision, and it is holding up a contributor's pull request rather than a roadmap item.
push_outputshas four channels today:stdout,file,webhookandslack.webhookis generic, a JSON POST to a URL you configure.slackis the only vendor-shaped one, in that it knows the payload that service wants.Telegram has now been offered twice as a fifth. I asked #3098 to drop it so we could settle this first, and #3167 has since implemented it independently and cleanly, so the question is due. Three ways to answer it.
A, keep adding vendor channels. About thirty lines and two settings keys each, off by default. Cheap on its own. The cost is that each one is permanent, we own its payload when the vendor changes it, and Discord, Teams and Mattermost all have the same claim the moment we say yes once.
B, a body template over
webhook. Telegram becomes configuration rather than code. The cost moves to the operator, who now writes the template, and a bad one fails at runtime instead of in review.C, hand it to a library. Apprise exists for exactly this. One
apprisechannel taking a list of URLs, andtgram://bottoken/chatidis the whole Telegram feature. What I measured rather than assumed:custom_jsonfor anything else.appriseandmarkdown.requests,requests-oauthlib,click,PyYAML 6.0.1andcertifi 2024.8.30are already there and unchanged.if "apprise" in channels:block inpush_outputs, the same shape as the existing four, plus two config keys. It delivered to a local sink with the title and markdown body intact on the first run. Theimport apprisesits inside the function, so operators who do not use it pay nothing.async_notifyand a concurrent dispatch path, so it is better than the blockingrequests.postwe use now.push_outputsis already host-only with an empty allowlist for the SSRF and exfiltration reasons inconfig_security.py:14-17, so they are already in the right place.C is unlike B in that the operator does not write a payload; the library owns each service's format. It is unlike A in that we never write another vendor channel.
On whether it is too bulky, since that was the first question asked of it. 1.7MB wheel, 5.3MB unpacked, of which 3.5MB is the 150 plugins and 744K is desktop-notification assets we would never touch. Dependencies are genuinely modular: the base install needs nothing per service, because Telegram, Slack, Discord, Teams and Mattermost are all plain HTTP through
requests, and only the exotic ones (MQTT, XMPP, Growl, PGP, SMPP) sit behind anall-pluginsextra we would not install. The code is not modular: all 150 ship regardless. Importing a single plugin directly costs 130ms instead of the full scan, but then we need a name-to-class map and we are writing vendor code again, which defeats the point.The honest costs of C. It is a new runtime dependency for a feature, and AGENTS.md says to ask before adding one, which is part of why I am asking. We inherit its cadence and its security surface, and we would be shipping 150 plugins to use one. The first send in a process triggers a one-time plugin scan of about 1.2 seconds, invisible in a webhook service but real in a short CLI run. It makes
slackandwebhookredundant, so we either deprecate them and break existing config or carry both. And operators parsing the currentwebhookJSON would lose that exact shape.I lean C, with
slackandwebhookkept as they are and no deprecation, so nothing existing breaks. Second choice A for Telegram alone, since #3167 already works.@naorpeled @DanaFineTLV @ofir-frd, and @dwin-gharibi @noooooooookro since you both wrote this.
Unlike #3147 this is not necessary post-v1 work. It is one channel, not a runtime, so a quick answer unblocks someone.
All reactions