Events: per-project rules with severities and five delivery channels #12

Merged
Gilles merged 1 commit from feat/10-events into master 2026-10-25 21:58:04 +00:00
Owner

Closes #10

Backend part of the multi-channel events feature. The UI comes in an argus/frontend PR, the upload metadata in an argus/upload-action PR.

What's in it

  • New apps.events app
    • EventRule: trigger + params, severity, ref/type filters, channels, recipients, extra emails.
    • EventRuleState keeps one row per rule, ref, type and variant, for de-duplication.
    • Event, EventDelivery, UserNotification, PushSubscription, PrComment.
  • Triggers
    • status_fail, status_warn, regression and recovery are evaluated after recompute_aggregate, with all variants combined.
    • coverage_below, coverage_drop (vs. the previous report or a baseline branch), failed_tests_above, processing_error and new_report are evaluated after process_report.
    • Each runs in its own Celery task, so a failing rule never fails report processing.
    • Condition triggers only fire on their false → true edge.
  • Channels
    • Each delivery runs in its own task: 3 retries with backoff, then failed. A channel that doesn't apply is skipped with a reason.
    • web: one notification per recipient, read/unread.
    • desktop: Web Push (pywebpush, VAPID). Expired subscriptions (404/410) are dropped.
    • email: HTML + text through the configured backend (poulpinou in prod).
    • Mattermost: bot account, colour-coded attachment.
    • PR comment: one comment per rule and PR, updated in place (<!-- argus-event:{rule_id} -->).
    • Recipients are only notified while they can still read the project.
  • API
    • projects/<o>/<r>/event-rules/: CRUD needs write; follow/ needs read; test/ sends a sample on desktop/email/Mattermost and records nothing.
    • event-rules/recipients/: user picker.
    • projects/<o>/<r>/events/ and events/: summary lists, filterable by severity, trigger, rule, ref, type, delivery state (incl. none) and period, paginated.
    • me/notifications/ and me/notifications/read/.
    • push/config/ and push/subscriptions/.
    • mattermost/channels/.
  • Upload metadata: Report.run_url and Report.actor, both optional upload fields, used in event messages.
  • Deploy
    • New env vars and two new secrets (argusMattermostBotToken, argusVapidPrivateKey) on web and worker.
    • Documented in deploy/README.md § 6.

Before merging

  • Create both secret files in /srv/docker/argus/secrets/; an empty file disables that channel. Docker refuses to start with a missing secret.
  • The Forgejo service token needs write:issue for PR comments (already done).

Not included

  • Grouping a CI matrix's new-report events into one. Today each variant raises its own new_report event.
  • The poulpinou bump to 1.1.0: that version isn't released yet, so 1.0.0 is kept.

Tests

34 new pytest cases (169 in total): every trigger, de-duplication, each channel mocked, retries, permissions, API filters, upload metadata. covers markers are added to features.catalog.yaml. pylint 10/10, autopep8 and bandit clean.

🤖 Generated with Claude Code

https://claude.ai/code/session_014BSmBtGWeFBD9z4mYm9SjA

Closes #10 Backend part of the multi-channel events feature. The UI comes in an argus/frontend PR, the upload metadata in an argus/upload-action PR. ## What's in it - **New `apps.events` app** - `EventRule`: trigger + params, severity, ref/type filters, channels, recipients, extra emails. - `EventRuleState` keeps one row per rule, ref, type and variant, for de-duplication. - `Event`, `EventDelivery`, `UserNotification`, `PushSubscription`, `PrComment`. - **Triggers** - `status_fail`, `status_warn`, `regression` and `recovery` are evaluated after `recompute_aggregate`, with all variants combined. - `coverage_below`, `coverage_drop` (vs. the previous report or a baseline branch), `failed_tests_above`, `processing_error` and `new_report` are evaluated after `process_report`. - Each runs in its own Celery task, so a failing rule never fails report processing. - Condition triggers only fire on their false → true edge. - **Channels** - Each delivery runs in its own task: 3 retries with backoff, then `failed`. A channel that doesn't apply is `skipped` with a reason. - **web**: one notification per recipient, read/unread. - **desktop**: Web Push (`pywebpush`, VAPID). Expired subscriptions (404/410) are dropped. - **email**: HTML + text through the configured backend (poulpinou in prod). - **Mattermost**: bot account, colour-coded attachment. - **PR comment**: one comment per rule and PR, updated in place (`<!-- argus-event:{rule_id} -->`). - Recipients are only notified while they can still read the project. - **API** - `projects/<o>/<r>/event-rules/`: CRUD needs write; `follow/` needs read; `test/` sends a sample on desktop/email/Mattermost and records nothing. - `event-rules/recipients/`: user picker. - `projects/<o>/<r>/events/` and `events/`: summary lists, filterable by severity, trigger, rule, ref, type, delivery state (incl. `none`) and period, paginated. - `me/notifications/` and `me/notifications/read/`. - `push/config/` and `push/subscriptions/`. - `mattermost/channels/`. - **Upload metadata**: `Report.run_url` and `Report.actor`, both optional upload fields, used in event messages. - **Deploy** - New env vars and two new secrets (`argusMattermostBotToken`, `argusVapidPrivateKey`) on web and worker. - Documented in `deploy/README.md` § 6. ## Before merging - Create both secret files in `/srv/docker/argus/secrets/`; an empty file disables that channel. Docker refuses to start with a missing secret. - The Forgejo service token needs `write:issue` for PR comments (already done). ## Not included - Grouping a CI matrix's new-report events into one. Today each variant raises its own `new_report` event. - The poulpinou bump to 1.1.0: that version isn't released yet, so 1.0.0 is kept. ## Tests 34 new pytest cases (169 in total): every trigger, de-duplication, each channel mocked, retries, permissions, API filters, upload metadata. `covers` markers are added to `features.catalog.yaml`. pylint 10/10, autopep8 and bandit clean. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_014BSmBtGWeFBD9z4mYm9SjA
Add events: per-project rules with severities, five delivery channels
All checks were successful
ci / test (pull_request) Successful in 3m10s
ci / e2e (pull_request) Has been skipped
ci / docker (pull_request) Has been skipped
ci / deploy (pull_request) Has been skipped
6b61016969
New apps.events app (argus/backend#10):
- EventRule per project: trigger (status fail/warn, regression,
  recovery, coverage below/drop, failed tests, processing error, new
  report), severity alert/warning/info (defaulted from the trigger),
  ref/type filters, channels, recipients + free email addresses.
- Events raised after process_report (report-level triggers) and
  recompute_aggregate (status triggers, all variants combined), with
  per (rule, ref, type, variant) state so a still-failing ref raises
  once until recovery. Always recorded, even with no channel.
- Delivery per channel in its own Celery task with retries: web
  (UserNotification, header bell), desktop (Web Push, VAPID), email
  (poulpinou), Mattermost (bot account, channel picker) and PR comment
  (one comment per rule and PR, updated in place). Only recipients who
  can still read the project are notified.
- API: event rules CRUD/follow/test, recipient picker, project and
  global event lists with filters, notifications, push subscriptions,
  Mattermost channels.
- Report.run_url/actor, optional upload fields from argus/upload-action.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014BSmBtGWeFBD9z4mYm9SjA
Author
Owner
<!-- argus-link-bot:argus/backend --> 📊 [Rapports Argus pour cette PR](https://reports.stationmyr.net/argus/backend/pr/12)
Gilles merged commit 99837b6cc6 into master 2026-10-25 21:58:04 +00:00
Gilles deleted branch feat/10-events 2026-10-25 21:58:04 +00:00
Sign in to join this conversation.
No description provided.