snapshot of https://github.com/zulip/zulip.git @ 48c69911c7dd4e03b20552eb3bd77ad8151c1357 (2026-09-15)
Some checks failed
Code scanning / CodeQL (push) Failing after 15s
Zulip production suite / Ubuntu 22.04 production build (push) Failing after 26s
Zulip production suite / Debian 12 production install with custom db name and user (push) Has been skipped
Zulip production suite / Ubuntu 22.04 production install and PostgreSQL upgrade with pgroonga (push) Has been skipped
Zulip production suite / Ubuntu 24.04 production install (push) Has been skipped
Zulip production suite / Ubuntu 26.04 production install (push) Has been skipped
Zulip production suite / Debian 13 production install (push) Has been skipped
Zulip production suite / 7.0 Version Upgrade (push) Has been skipped
Zulip production suite / 8.0 Version Upgrade (push) Has been skipped
Zulip production suite / 6.0 Version Upgrade (push) Has been skipped
Zulip production suite / 10.0 Version Upgrade (push) Has been skipped
Zulip production suite / 9.0 Version Upgrade (push) Has been skipped
Zulip production suite / 12.0 Version Upgrade (push) Has been skipped
Zulip production suite / 11.0 Version Upgrade (push) Has been skipped
GitHub Actions Security Analysis with zizmor / zizmor (push) Failing after 3s
Zulip CI / Debian 12 (Python 3.11, backend + documentation) (push) Failing after 26s
Zulip CI / Ubuntu 22.04 (Python 3.10, backend + frontend) (push) Failing after 3s
Zulip CI / Ubuntu 24.04 (Python 3.12, backend) (push) Failing after 25s
Zulip CI / Ubuntu 26.04 (Python 3.14, backend) (push) Failing after 25s
Zulip CI / Debian 13 (Python 3.13, backend) (push) Failing after 28s
Zulip production suite / Required jobs (push) Has been cancelled
Zulip CI / Required jobs (push) Has been cancelled
API Documentation Update Check / check-feature-level-updated (push) Has been cancelled
API Documentation Update Check / notify-if-api-docs-changed (push) Has been cancelled

This commit is contained in:
upstream-mirror
2026-09-15 15:05:30 +05:00
commit 64898b2c79
8999 changed files with 1757358 additions and 0 deletions

View File

View File

@@ -0,0 +1,39 @@
# Zulip Splunk integration
See your Splunk Search alerts in Zulip!
{start_tabs}
1. {!create-an-incoming-webhook.md!}
1. {!generate-webhook-url-basic.md!}
!!! tip ""
If you do not specify a topic, the name of the search will be used
as the topic (truncated if it's too long).
1. In the Splunk search app, execute the search you'd like to be
notified about. Click on **Save As** in the top-right corner,
and select **Alert**.
1. Configure the **Settings** and **Trigger Conditions** for your search
as appropriate. Under **Trigger Actions**, click **Add Actions**,
and select **Webhook**. Set **URL** to the URL generated above,
and click **Save**.
!!! tip ""
You can create as many search alerts as you like, with whatever
channel and topic you choose. Just generate the webhook URL as
appropriate for each one.
{end_tabs}
{!congrats.md!}
![](/static/images/integrations/splunk/001.png)
### Related documentation
{!webhooks-url-specification.md!}

View File

@@ -0,0 +1,46 @@
{
"results_link": "http://example.com:8000/app/search/search?q=%7Cloadjob%20rt_scheduler__admin__search__sudo_at_1483557185_2.2%20%7C%20head%201%20%7C%20tail%201&earliest=0&latest=now",
"app": "search",
"result": {
"timestartpos": "0",
"_serial": "2",
"splunk_server": "myserver",
"date_month": "january",
"USER": "",
"date_second": "32",
"source": "/var/log/auth.log",
"timeendpos": "15",
"_si": [
"myserver",
"main"
],
"punct": "___::_-_:_(:):_____",
"host": "myserver",
"TTY": "",
"_raw": "Jan 4 11:14:32 myserver sudo: pam_unix(sudo:session): session closed for user root",
"_sourcetype": "syslog",
"index": "main",
"date_minute": "14",
"date_year": "2017",
"_kv": "1",
"process": "sudo",
"PWD": "",
"pid": "",
"_time": "1483557272",
"uid": "",
"date_zone": "local",
"sourcetype": "syslog",
"_indextime": "1483557272",
"date_hour": "11",
"date_mday": "4",
"linecount": "",
"eventtype": "",
"COMMAND": "",
"_eventtype_color": "",
"date_wday": "wednesday",
"_confstr": "source::/var/log/auth.log|host::myserver|syslog"
},
"sid": "rt_scheduler__admin__search__sudo_at_1483557185_2.2",
"search_name": "this-search's-got-47-words-37-sentences-58-words-we-wanna-know-details-of-the-search-time-of-the-search-and-any-other-kind-of-thing-you-gotta-say-pertaining-to-and-about-the-search-I-want-to-know-authenticated-user's-name-and-any-other-kind-of-thing-you-gotta-say",
"owner": "admin"
}

View File

@@ -0,0 +1,45 @@
{
"results_link": "http://example.com:8000/app/search/search?q=%7Cloadjob%20rt_scheduler__admin__search__sudo_at_1483557185_2.2%20%7C%20head%201%20%7C%20tail%201&earliest=0&latest=now",
"app": "search",
"result": {
"timestartpos": "0",
"_serial": "2",
"splunk_server": "myserver",
"date_month": "january",
"USER": "",
"date_second": "32",
"source": "/var/log/auth.log",
"timeendpos": "15",
"_si": [
"myserver",
"main"
],
"punct": "___::_-_:_(:):_____",
"TTY": "",
"_raw": "Jan 4 11:14:32 myserver sudo: pam_unix(sudo:session): session closed for user root",
"_sourcetype": "syslog",
"index": "main",
"date_minute": "14",
"date_year": "2017",
"_kv": "1",
"process": "sudo",
"PWD": "",
"pid": "",
"_time": "1483557272",
"uid": "",
"date_zone": "local",
"sourcetype": "syslog",
"_indextime": "1483557272",
"date_hour": "11",
"date_mday": "4",
"linecount": "",
"eventtype": "",
"COMMAND": "",
"_eventtype_color": "",
"date_wday": "wednesday",
"_confstr": "source::/var/log/auth.log|host::myserver|syslog"
},
"sid": "rt_scheduler__admin__search__sudo_at_1483557185_2.2",
"search_name": "sudo",
"owner": "admin"
}

View File

@@ -0,0 +1,45 @@
{
"results_link": "http://example.com:8000/app/search/search?q=%7Cloadjob%20rt_scheduler__admin__search__sudo_at_1483557185_2.2%20%7C%20head%201%20%7C%20tail%201&earliest=0&latest=now",
"app": "search",
"result": {
"timestartpos": "0",
"_serial": "2",
"splunk_server": "myserver",
"date_month": "january",
"USER": "",
"date_second": "32",
"source": "/var/log/auth.log",
"timeendpos": "15",
"_si": [
"myserver",
"main"
],
"punct": "___::_-_:_(:):_____",
"host": "myserver",
"TTY": "",
"_sourcetype": "syslog",
"index": "main",
"date_minute": "14",
"date_year": "2017",
"_kv": "1",
"process": "sudo",
"PWD": "",
"pid": "",
"_time": "1483557272",
"uid": "",
"date_zone": "local",
"sourcetype": "syslog",
"_indextime": "1483557272",
"date_hour": "11",
"date_mday": "4",
"linecount": "",
"eventtype": "",
"COMMAND": "",
"_eventtype_color": "",
"date_wday": "wednesday",
"_confstr": "source::/var/log/auth.log|host::myserver|syslog"
},
"sid": "rt_scheduler__admin__search__sudo_at_1483557185_2.2",
"search_name": "sudo",
"owner": "admin"
}

View File

@@ -0,0 +1,45 @@
{
"app": "search",
"result": {
"timestartpos": "0",
"_serial": "2",
"splunk_server": "myserver",
"date_month": "january",
"USER": "",
"date_second": "32",
"source": "/var/log/auth.log",
"timeendpos": "15",
"_si": [
"myserver",
"main"
],
"punct": "___::_-_:_(:):_____",
"host": "myserver",
"TTY": "",
"_raw": "Jan 4 11:14:32 myserver sudo: pam_unix(sudo:session): session closed for user root",
"_sourcetype": "syslog",
"index": "main",
"date_minute": "14",
"date_year": "2017",
"_kv": "1",
"process": "sudo",
"PWD": "",
"pid": "",
"_time": "1483557272",
"uid": "",
"date_zone": "local",
"sourcetype": "syslog",
"_indextime": "1483557272",
"date_hour": "11",
"date_mday": "4",
"linecount": "",
"eventtype": "",
"COMMAND": "",
"_eventtype_color": "",
"date_wday": "wednesday",
"_confstr": "source::/var/log/auth.log|host::myserver|syslog"
},
"sid": "rt_scheduler__admin__search__sudo_at_1483557185_2.2",
"search_name": "sudo",
"owner": "admin"
}

View File

@@ -0,0 +1,45 @@
{
"results_link": "http://example.com:8000/app/search/search?q=%7Cloadjob%20rt_scheduler__admin__search__sudo_at_1483557185_2.2%20%7C%20head%201%20%7C%20tail%201&earliest=0&latest=now",
"app": "search",
"result": {
"timestartpos": "0",
"_serial": "2",
"splunk_server": "myserver",
"date_month": "january",
"USER": "",
"date_second": "32",
"source": "/var/log/auth.log",
"timeendpos": "15",
"_si": [
"myserver",
"main"
],
"punct": "___::_-_:_(:):_____",
"host": "myserver",
"TTY": "",
"_raw": "Jan 4 11:14:32 myserver sudo: pam_unix(sudo:session): session closed for user root",
"_sourcetype": "syslog",
"index": "main",
"date_minute": "14",
"date_year": "2017",
"_kv": "1",
"process": "sudo",
"PWD": "",
"pid": "",
"_time": "1483557272",
"uid": "",
"date_zone": "local",
"sourcetype": "syslog",
"_indextime": "1483557272",
"date_hour": "11",
"date_mday": "4",
"linecount": "",
"eventtype": "",
"COMMAND": "",
"_eventtype_color": "",
"date_wday": "wednesday",
"_confstr": "source::/var/log/auth.log|host::myserver|syslog"
},
"sid": "rt_scheduler__admin__search__sudo_at_1483557185_2.2",
"owner": "admin"
}

View File

@@ -0,0 +1,45 @@
{
"results_link": "http://example.com:8000/app/search/search?q=%7Cloadjob%20rt_scheduler__admin__search__sudo_at_1483557185_2.2%20%7C%20head%201%20%7C%20tail%201&earliest=0&latest=now",
"app": "search",
"result": {
"timestartpos": "0",
"_serial": "2",
"splunk_server": "myserver",
"date_month": "january",
"USER": "",
"date_second": "32",
"timeendpos": "15",
"_si": [
"myserver",
"main"
],
"punct": "___::_-_:_(:):_____",
"host": "myserver",
"TTY": "",
"_raw": "Jan 4 11:14:32 myserver sudo: pam_unix(sudo:session): session closed for user root",
"_sourcetype": "syslog",
"index": "main",
"date_minute": "14",
"date_year": "2017",
"_kv": "1",
"process": "sudo",
"PWD": "",
"pid": "",
"_time": "1483557272",
"uid": "",
"date_zone": "local",
"sourcetype": "syslog",
"_indextime": "1483557272",
"date_hour": "11",
"date_mday": "4",
"linecount": "",
"eventtype": "",
"COMMAND": "",
"_eventtype_color": "",
"date_wday": "wednesday",
"_confstr": "source::/var/log/auth.log|host::myserver|syslog"
},
"sid": "rt_scheduler__admin__search__sudo_at_1483557185_2.2",
"search_name": "sudo",
"owner": "admin"
}

View File

@@ -0,0 +1,46 @@
{
"results_link": "http://example.com:8000/app/search/search?q=%7Cloadjob%20rt_scheduler__admin__search__sudo_at_1483557185_2.2%20%7C%20head%201%20%7C%20tail%201&earliest=0&latest=now",
"app": "search",
"result": {
"timestartpos": "0",
"_serial": "2",
"splunk_server": "myserver",
"date_month": "january",
"USER": "",
"date_second": "32",
"source": "/var/log/auth.log",
"timeendpos": "15",
"_si": [
"myserver",
"main"
],
"punct": "___::_-_:_(:):_____",
"host": "myserver",
"TTY": "",
"_raw": "Jan 4 11:14:32 myserver sudo: pam_unix(sudo:session): session closed for user root",
"_sourcetype": "syslog",
"index": "main",
"date_minute": "14",
"date_year": "2017",
"_kv": "1",
"process": "sudo",
"PWD": "",
"pid": "",
"_time": "1483557272",
"uid": "",
"date_zone": "local",
"sourcetype": "syslog",
"_indextime": "1483557272",
"date_hour": "11",
"date_mday": "4",
"linecount": "",
"eventtype": "",
"COMMAND": "",
"_eventtype_color": "",
"date_wday": "wednesday",
"_confstr": "source::/var/log/auth.log|host::myserver|syslog"
},
"sid": "rt_scheduler__admin__search__sudo_at_1483557185_2.2",
"search_name": "sudo",
"owner": "admin"
}

View File

@@ -0,0 +1,46 @@
{
"results_link": "http://example.com:8000/app/search/search?q=%7Cloadjob%20rt_scheduler__admin__search__sudo_at_1483557185_2.2%20%7C%20head%201%20%7C%20tail%201&earliest=0&latest=now",
"app": "search",
"result": {
"timestartpos": "0",
"_serial": "2",
"splunk_server": "myserver",
"date_month": "january",
"USER": "",
"date_second": "32",
"source": "/var/log/auth.log",
"timeendpos": "15",
"_si": [
"myserver",
"main"
],
"punct": "___::_-_:_(:):_____",
"host": "myserver",
"TTY": "",
"_raw": "Jan 4 11:14:32 myserver sudo: pam_unix(sudo:session): session closed for user root",
"_sourcetype": "syslog",
"index": "main",
"date_minute": "14",
"date_year": "2017",
"_kv": "1",
"process": "sudo",
"PWD": "",
"pid": "",
"_time": "1483557272",
"uid": "",
"date_zone": "local",
"sourcetype": "syslog",
"_indextime": "1483557272",
"date_hour": "11",
"date_mday": "4",
"linecount": "",
"eventtype": "",
"COMMAND": "",
"_eventtype_color": "",
"date_wday": "wednesday",
"_confstr": "source::/var/log/auth.log|host::myserver|syslog"
},
"sid": "rt_scheduler__admin__search__sudo_at_1483557185_2.2",
"search_name": "This search's name isn't that long",
"owner": "admin"
}

View File

@@ -0,0 +1,155 @@
from zerver.lib.test_classes import WebhookTestCase
class SplunkHookTests(WebhookTestCase):
def test_splunk_search_one_result(self) -> None:
self.url = self.build_webhook_url(topic="New Search Alert")
# define the expected message contents
expected_topic_name = "New Search Alert"
expected_message = """
Splunk alert from saved search:
* **Search**: [sudo](http://example.com:8000/app/search/search?q=%7Cloadjob%20rt_scheduler__admin__search__sudo_at_1483557185_2.2%20%7C%20head%201%20%7C%20tail%201&earliest=0&latest=now)
* **Host**: myserver
* **Source**: `/var/log/auth.log`
* **Raw**: `Jan 4 11:14:32 myserver sudo: pam_unix(sudo:session): session closed for user root`
""".strip()
# using fixture named splunk_search_one_result, execute this test
self.check_webhook(
"search_one_result",
expected_topic_name,
expected_message,
content_type="application/x-www-form-urlencoded",
)
def test_splunk_short_search_name(self) -> None:
# don't provide a topic so the search name is used instead
expected_topic_name = "This search's name isn't that long"
expected_message = """
Splunk alert from saved search:
* **Search**: [This search's name isn't that long](http://example.com:8000/app/search/search?q=%7Cloadjob%20rt_scheduler__admin__search__sudo_at_1483557185_2.2%20%7C%20head%201%20%7C%20tail%201&earliest=0&latest=now)
* **Host**: myserver
* **Source**: `/var/log/auth.log`
* **Raw**: `Jan 4 11:14:32 myserver sudo: pam_unix(sudo:session): session closed for user root`
""".strip()
self.check_webhook(
"short_search_name",
expected_topic_name,
expected_message,
content_type="application/x-www-form-urlencoded",
)
def test_splunk_long_search_name(self) -> None:
# don't provide a topic so the search name is used instead
expected_topic_name = "this-search's-got-47-words-37-sentences-58-words-we-wanna..."
expected_message = """
Splunk alert from saved search:
* **Search**: [this-search's-got-47-words-37-sentences-58-words-we-wanna-know-details-of-the-search-time-of-the-search-and-any-other-kind-of-thing-you-gotta-say-pertaining-to-and-about-the-search-I-want-to-know-authenticated-user's-name-and-any-other-kind-of-thing-you-gotta-say](http://example.com:8000/app/search/search?q=%7Cloadjob%20rt_scheduler__admin__search__sudo_at_1483557185_2.2%20%7C%20head%201%20%7C%20tail%201&earliest=0&latest=now)
* **Host**: myserver
* **Source**: `/var/log/auth.log`
* **Raw**: `Jan 4 11:14:32 myserver sudo: pam_unix(sudo:session): session closed for user root`
""".strip()
self.check_webhook(
"long_search_name",
expected_topic_name,
expected_message,
content_type="application/x-www-form-urlencoded",
)
def test_splunk_missing_results_link(self) -> None:
self.url = self.build_webhook_url(topic="New Search Alert")
expected_topic_name = "New Search Alert"
expected_message = """
Splunk alert from saved search:
* **Search**: [sudo](Missing results_link)
* **Host**: myserver
* **Source**: `/var/log/auth.log`
* **Raw**: `Jan 4 11:14:32 myserver sudo: pam_unix(sudo:session): session closed for user root`
""".strip()
self.check_webhook(
"missing_results_link",
expected_topic_name,
expected_message,
content_type="application/x-www-form-urlencoded",
)
def test_splunk_missing_search_name(self) -> None:
self.url = self.build_webhook_url(topic="New Search Alert")
expected_topic_name = "New Search Alert"
expected_message = """
Splunk alert from saved search:
* **Search**: [Missing search_name](http://example.com:8000/app/search/search?q=%7Cloadjob%20rt_scheduler__admin__search__sudo_at_1483557185_2.2%20%7C%20head%201%20%7C%20tail%201&earliest=0&latest=now)
* **Host**: myserver
* **Source**: `/var/log/auth.log`
* **Raw**: `Jan 4 11:14:32 myserver sudo: pam_unix(sudo:session): session closed for user root`
""".strip()
self.check_webhook(
"missing_search_name",
expected_topic_name,
expected_message,
content_type="application/x-www-form-urlencoded",
)
def test_splunk_missing_host(self) -> None:
self.url = self.build_webhook_url(topic="New Search Alert")
expected_topic_name = "New Search Alert"
expected_message = """
Splunk alert from saved search:
* **Search**: [sudo](http://example.com:8000/app/search/search?q=%7Cloadjob%20rt_scheduler__admin__search__sudo_at_1483557185_2.2%20%7C%20head%201%20%7C%20tail%201&earliest=0&latest=now)
* **Host**: Missing host
* **Source**: `/var/log/auth.log`
* **Raw**: `Jan 4 11:14:32 myserver sudo: pam_unix(sudo:session): session closed for user root`
""".strip()
self.check_webhook(
"missing_host",
expected_topic_name,
expected_message,
content_type="application/x-www-form-urlencoded",
)
def test_splunk_missing_source(self) -> None:
self.url = self.build_webhook_url(topic="New Search Alert")
expected_topic_name = "New Search Alert"
expected_message = """
Splunk alert from saved search:
* **Search**: [sudo](http://example.com:8000/app/search/search?q=%7Cloadjob%20rt_scheduler__admin__search__sudo_at_1483557185_2.2%20%7C%20head%201%20%7C%20tail%201&earliest=0&latest=now)
* **Host**: myserver
* **Source**: `Missing source`
* **Raw**: `Jan 4 11:14:32 myserver sudo: pam_unix(sudo:session): session closed for user root`
""".strip()
self.check_webhook(
"missing_source",
expected_topic_name,
expected_message,
content_type="application/x-www-form-urlencoded",
)
def test_splunk_missing_raw(self) -> None:
self.url = self.build_webhook_url(topic="New Search Alert")
expected_topic_name = "New Search Alert"
expected_message = """
Splunk alert from saved search:
* **Search**: [sudo](http://example.com:8000/app/search/search?q=%7Cloadjob%20rt_scheduler__admin__search__sudo_at_1483557185_2.2%20%7C%20head%201%20%7C%20tail%201&earliest=0&latest=now)
* **Host**: myserver
* **Source**: `/var/log/auth.log`
* **Raw**: `Missing _raw`
""".strip()
self.check_webhook(
"missing_raw",
expected_topic_name,
expected_message,
content_type="application/x-www-form-urlencoded",
)

View File

@@ -0,0 +1,54 @@
# Webhooks for external integrations.
from django.http import HttpRequest, HttpResponse
from zerver.decorator import webhook_view
from zerver.lib.response import json_success
from zerver.lib.typed_endpoint import JsonBodyPayload, typed_endpoint
from zerver.lib.validator import WildValue, check_string
from zerver.lib.webhooks.common import check_send_webhook_message
from zerver.models import UserProfile
from zerver.models.constants import MAX_TOPIC_NAME_LENGTH
MESSAGE_TEMPLATE = """
Splunk alert from saved search:
* **Search**: [{search}]({link})
* **Host**: {host}
* **Source**: `{source}`
* **Raw**: `{raw}`
""".strip()
@webhook_view("Splunk")
@typed_endpoint
def api_splunk_webhook(
request: HttpRequest,
user_profile: UserProfile,
*,
payload: JsonBodyPayload[WildValue],
) -> HttpResponse:
# use default values if expected data is not provided
search_name = payload.get("search_name", "Missing search_name").tame(check_string)
results_link = payload.get("results_link", "Missing results_link").tame(check_string)
host = payload.get("result", {}).get("host", "Missing host").tame(check_string)
source = payload.get("result", {}).get("source", "Missing source").tame(check_string)
raw = payload.get("result", {}).get("_raw", "Missing _raw").tame(check_string)
# for the default topic, use search name but truncate if too long
if len(search_name) >= MAX_TOPIC_NAME_LENGTH:
topic_name = f"{search_name[: (MAX_TOPIC_NAME_LENGTH - 3)]}..."
else:
topic_name = search_name
# construct the message body
body = MESSAGE_TEMPLATE.format(
search=search_name,
link=results_link,
host=host,
source=source,
raw=raw,
)
# send the message
check_send_webhook_message(request, user_profile, topic_name, body)
return json_success(request)