···11+# Byte-compiled / optimized / DLL files
22+__pycache__/
33+*.py[codz]
44+*$py.class
55+66+# C extensions
77+*.so
88+99+# Distribution / packaging
1010+.Python
1111+build/
1212+develop-eggs/
1313+dist/
1414+downloads/
1515+eggs/
1616+.eggs/
1717+lib/
1818+lib64/
1919+parts/
2020+sdist/
2121+var/
2222+wheels/
2323+share/python-wheels/
2424+*.egg-info/
2525+.installed.cfg
2626+*.egg
2727+MANIFEST
2828+2929+# PyInstaller
3030+# Usually these files are written by a python script from a template
3131+# before PyInstaller builds the exe, so as to inject date/other infos into it.
3232+*.manifest
3333+*.spec
3434+3535+# Installer logs
3636+pip-log.txt
3737+pip-delete-this-directory.txt
3838+3939+# Unit test / coverage reports
4040+htmlcov/
4141+.tox/
4242+.nox/
4343+.coverage
4444+.coverage.*
4545+.cache
4646+nosetests.xml
4747+coverage.xml
4848+*.cover
4949+*.py.cover
5050+.hypothesis/
5151+.pytest_cache/
5252+cover/
5353+5454+# Translations
5555+*.mo
5656+*.pot
5757+5858+# Django stuff:
5959+*.log
6060+local_settings.py
6161+db.sqlite3
6262+db.sqlite3-journal
6363+6464+# Flask stuff:
6565+instance/
6666+.webassets-cache
6767+6868+# Scrapy stuff:
6969+.scrapy
7070+7171+# Sphinx documentation
7272+docs/_build/
7373+7474+# PyBuilder
7575+.pybuilder/
7676+target/
7777+7878+# Jupyter Notebook
7979+.ipynb_checkpoints
8080+8181+# IPython
8282+profile_default/
8383+ipython_config.py
8484+8585+# pyenv
8686+# For a library or package, you might want to ignore these files since the code is
8787+# intended to run in multiple environments; otherwise, check them in:
8888+# .python-version
8989+9090+# pipenv
9191+# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
9292+# However, in case of collaboration, if having platform-specific dependencies or dependencies
9393+# having no cross-platform support, pipenv may install dependencies that don't work, or not
9494+# install all needed dependencies.
9595+#Pipfile.lock
9696+9797+# UV
9898+# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
9999+# This is especially recommended for binary packages to ensure reproducibility, and is more
100100+# commonly ignored for libraries.
101101+#uv.lock
102102+103103+# poetry
104104+# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
105105+# This is especially recommended for binary packages to ensure reproducibility, and is more
106106+# commonly ignored for libraries.
107107+# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
108108+#poetry.lock
109109+#poetry.toml
110110+111111+# pdm
112112+# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
113113+# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
114114+# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
115115+#pdm.lock
116116+#pdm.toml
117117+.pdm-python
118118+.pdm-build/
119119+120120+# pixi
121121+# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
122122+#pixi.lock
123123+# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
124124+# in the .venv directory. It is recommended not to include this directory in version control.
125125+.pixi
126126+127127+# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
128128+__pypackages__/
129129+130130+# Celery stuff
131131+celerybeat-schedule
132132+celerybeat.pid
133133+134134+# SageMath parsed files
135135+*.sage.py
136136+137137+# Environments
138138+.env
139139+.envrc
140140+.venv
141141+env/
142142+venv/
143143+ENV/
144144+env.bak/
145145+venv.bak/
146146+147147+# Spyder project settings
148148+.spyderproject
149149+.spyproject
150150+151151+# Rope project settings
152152+.ropeproject
153153+154154+# mkdocs documentation
155155+/site
156156+157157+# mypy
158158+.mypy_cache/
159159+.dmypy.json
160160+dmypy.json
161161+162162+# Pyre type checker
163163+.pyre/
164164+165165+# pytype static type analyzer
166166+.pytype/
167167+168168+# Cython debug symbols
169169+cython_debug/
170170+171171+# PyCharm
172172+# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
173173+# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
174174+# and can be added to the global gitignore or merged into this file. For a more nuclear
175175+# option (not recommended) you can uncomment the following to ignore the entire idea folder.
176176+#.idea/
177177+178178+# Abstra
179179+# Abstra is an AI-powered process automation framework.
180180+# Ignore directories containing user credentials, local state, and settings.
181181+# Learn more at https://abstra.io/docs
182182+.abstra/
183183+184184+# Visual Studio Code
185185+# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
186186+# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
187187+# and can be added to the global gitignore or merged into this file. However, if you prefer,
188188+# you could uncomment the following to ignore the entire vscode folder
189189+# .vscode/
190190+191191+# Ruff stuff:
192192+.ruff_cache/
193193+194194+# PyPI configuration file
195195+.pypirc
196196+197197+# Marimo
198198+marimo/_static/
199199+marimo/_lsp/
200200+__marimo__/
201201+202202+# Streamlit
203203+.streamlit/secrets.toml
204204+205205+thicket.yaml
206206+bot-config/zuliprc
···11+# Netdata Zulip Bot - Development Instructions
22+33+This repository implements a Zulip bot that receives incoming webhook notifications from Netdata Cloud and posts the resulting notifications to a Zulip topic.
44+55+## Core Requirements
66+77+### Technology Stack
88+- **Language**: Python with `uv` package manager
99+- **Framework**: Python `zulip_bots` PyPI package for Zulip integration
1010+- **Web Server**: FastAPI for webhook endpoint
1111+- **Deployment**: Standalone service
1212+1313+### Netdata Integration
1414+- **Webhook Format**: Follow the Netdata Cloud webhook notification format from:
1515+ - URL: `https://raw.githubusercontent.com/netdata/netdata/refs/heads/master/integrations/cloud-notifications/metadata.yaml`
1616+ - Section: `id: notify-cloud-webhook`
1717+- **Notification Types**: Handle both alert notifications and reachability notifications
1818+1919+### Zulip Configuration
2020+- **Configuration Source**: The `.zuliprc` file should contain:
2121+ - Zulip site URL
2222+ - Bot email and API key
2323+ - Target stream/channel for posting messages
2424+- **Topic Organization**: Messages should be posted to topics based on severity:
2525+ - `critical`, `warning`, `clear` for alerts
2626+ - `reachability` for host status changes
2727+- **Message Format**: Rich markdown with:
2828+ - Alert details and timestamps
2929+ - Markdown-formatted alert URLs for easy access to Netdata Cloud
3030+3131+### Security Requirements
3232+- **TLS/HTTPS**: The service must listen on HTTPS (not HTTP)
3333+- **Let's Encrypt**: Use Let's Encrypt to automatically issue SSL certificates for the public hostname
3434+- **Mutual TLS**: Netdata uses mutual TLS for authentication
3535+ - The server must validate Netdata's client certificate
3636+ - Support configuration of client CA certificate path
3737+3838+### Service Architecture
3939+- **Standalone Service**: Run as an independent service
4040+- **Webhook Endpoint**: Expose `/webhook/netdata` for receiving notifications
4141+- **Health Check**: Provide `/health` endpoint for monitoring
4242+- **Structured Logging**: Use JSON-structured logs for production monitoring
4343+4444+## Implementation Notes
4545+4646+### Configuration Management
4747+- Support both `.zuliprc` file and environment variables
4848+- Provide sample configuration files with `--create-config` flag
4949+- Server configuration via environment variables:
5050+ - `SERVER_DOMAIN`: Public domain for Let's Encrypt
5151+ - `SERVER_PORT`: HTTPS port (default: 8443)
5252+ - `SERVER_ENABLE_MTLS`: Enable mutual TLS
5353+ - `SERVER_CLIENT_CA_PATH`: Path to Netdata client CA
5454+5555+### Message Processing
5656+1. Receive Netdata webhook POST request
5757+2. Validate and parse JSON payload
5858+3. Determine notification type (alert vs reachability)
5959+4. Format message with appropriate emoji and markdown
6060+5. Send to configured Zulip stream/topic
6161+6262+### Error Handling
6363+- Validate all incoming payloads
6464+- Log errors without exposing internal details
6565+- Return appropriate HTTP status codes
6666+- Implement retry logic for Zulip API failures
6767+6868+## Testing
6969+7070+Run tests with:
7171+```bash
7272+uv run python -m pytest tests/ -v
7373+```
7474+7575+## Deployment
7676+7777+The service should be deployable via:
7878+- Systemd service (see `examples/netdata-zulip-bot.service`)
7979+- Docker container (see `Dockerfile` and `docker-compose.yml`)
8080+- Automated setup script (`scripts/setup.sh`)
8181+8282+## Development Commands
8383+8484+- **Install dependencies**: `uv sync`
8585+- **Create config samples**: `uv run netdata-zulip-bot --create-config`
8686+- **Run tests**: `uv run python -m pytest tests/`
8787+- **Start service**: `uv run netdata-zulip-bot`
8888+8989+## Important Reminders
9090+9191+- Always validate Netdata webhook payloads before processing
9292+- Ensure SSL certificates are properly configured before production deployment
9393+- Test mutual TLS authentication with actual Netdata Cloud webhooks
9494+- Monitor service logs for webhook processing errors
9595+- Keep Zulip API credentials secure and never commit them to the repository