Organization-level and global event rules #35

Merged
Gilles merged 27 commits from feat/21-org-global-rules into master 2026-10-28 23:01:01 +00:00
Owner

Closes #21

Part of the server monitoring plan (phase 2.3). Stacked on #34 (base feat/23-metric-thresholds).

Changes

  • EventRule.project becomes optional and EventRule.organization is added (check constraint: at most one). Scopes: project, organization (applies to all its projects), global (both empty, applies to every project). scope / scope_label exposed by the API.
  • Engine: matching includes the project's own, its organization's and the global rules (also for metric thresholds and the stale check). EventRuleState gains project (state per project, so an org/global rule behaves like one rule per project); events always belong to the report's project.
  • PrComment gains project (an org/global rule comments on several repos).
  • Migration events/0006: adds the fields, copies each rule's project onto existing states and PR comments, then makes them non-null. Checked forward and backward on a database with existing rows.
  • API: the rule views are scope-generic (apps.events.scopes.RuleScope) and routed three times: /api/projects/<o>/<r>/event-rules/… (unchanged), /api/organizations/<org>/event-rules/… (org read/write level), /api/event-rules/… (Argus admins only). A project's GET …/event-rules/?include_inherited=1 also lists its organization's and the global rules, read-only and without recipients/extra emails. "Test this rule" on an org/global rule is staged on one of its readable projects.
  • De-duplication: when several rules raise the same occurrence (same project, report, stream, trigger and text), each target (Mattermost channel/user, email address, Argus user, push subscription, PR) is notified once per channel — SentTarget rows claimed through a unique constraint (race-free between concurrent deliveries), kept one hour.
  • README, feature catalog; tests in apps/events/test_scopes.py.

Checks

pytest (225 passed), pylint 10/10, autopep8, bandit clean.

🤖 Generated with Claude Code

https://claude.ai/code/session_014BSmBtGWeFBD9z4mYm9SjA

Closes #21 Part of the server monitoring plan (phase 2.3). **Stacked on #34** (base `feat/23-metric-thresholds`). ## Changes - `EventRule.project` becomes optional and `EventRule.organization` is added (check constraint: at most one). Scopes: project, organization (applies to all its projects), global (both empty, applies to every project). `scope` / `scope_label` exposed by the API. - Engine: matching includes the project's own, its organization's and the global rules (also for metric thresholds and the stale check). `EventRuleState` gains `project` (state per project, so an org/global rule behaves like one rule per project); events always belong to the **report's** project. - `PrComment` gains `project` (an org/global rule comments on several repos). - Migration `events/0006`: adds the fields, **copies each rule's project onto existing states and PR comments**, then makes them non-null. Checked forward and backward on a database with existing rows. - API: the rule views are scope-generic (`apps.events.scopes.RuleScope`) and routed three times: `/api/projects/<o>/<r>/event-rules/…` (unchanged), `/api/organizations/<org>/event-rules/…` (org read/write level), `/api/event-rules/…` (Argus admins only). A project's `GET …/event-rules/?include_inherited=1` also lists its organization's and the global rules, read-only and without recipients/extra emails. "Test this rule" on an org/global rule is staged on one of its readable projects. - De-duplication: when several rules raise the same occurrence (same project, report, stream, trigger and text), each target (Mattermost channel/user, email address, Argus user, push subscription, PR) is notified once per channel — `SentTarget` rows claimed through a unique constraint (race-free between concurrent deliveries), kept one hour. - README, feature catalog; tests in `apps/events/test_scopes.py`. ## Checks pytest (225 passed), pylint 10/10, autopep8, bandit clean. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_014BSmBtGWeFBD9z4mYm9SjA
feature: organization-level and global event rules
All checks were successful
ci / test (pull_request) Successful in 3m21s
ci / e2e (pull_request) Has been skipped
ci / docker (pull_request) Has been skipped
ci / deploy (pull_request) Has been skipped
8f90e471e0
- An event rule belongs to a project, an organization (all its
  projects) or nothing (global, Argus admins only). Same API under
  /projects/<o>/<r>/, /organizations/<org>/ and / ; a project can list
  its inherited rules (?include_inherited=1, read-only, no recipients).
- Rule state and PR comments are tracked per project (data migration
  copies the rule's project onto existing rows).
- Events belong to the report's project, whatever the rule's scope.
- Twin events (same occurrence raised by several rules) notify each
  target once per channel: SentTarget claims, race-free through a
  unique constraint, one-hour window.

Closes #21

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/35)
Merge branch 'feat/23-metric-thresholds' into feat/21-org-global-rules
All checks were successful
ci / test (pull_request) Successful in 3m20s
ci / e2e (pull_request) Has been skipped
ci / docker (pull_request) Has been skipped
ci / deploy (pull_request) Has been skipped
160cbe8b41
Merge branch 'feat/23-metric-thresholds' into feat/21-org-global-rules
Some checks failed
ci / test (pull_request) Has been cancelled
ci / e2e (pull_request) Has been cancelled
ci / docker (pull_request) Has been cancelled
ci / deploy (pull_request) Has been cancelled
9abef61d44
Merge branch 'feat/23-metric-thresholds' into feat/21-org-global-rules
All checks were successful
ci / test (pull_request) Successful in 3m19s
ci / e2e (pull_request) Has been skipped
ci / docker (pull_request) Has been skipped
ci / deploy (pull_request) Has been skipped
52d72a2412
Merge branch 'feat/23-metric-thresholds' into feat/21-org-global-rules
Some checks failed
ci / test (pull_request) Has been cancelled
ci / e2e (pull_request) Has been cancelled
ci / docker (pull_request) Has been cancelled
ci / deploy (pull_request) Has been cancelled
4d1b6c0998
Merge branch 'feat/23-metric-thresholds' into feat/21-org-global-rules
Some checks failed
ci / test (pull_request) Has been cancelled
ci / e2e (pull_request) Has been cancelled
ci / docker (pull_request) Has been cancelled
ci / deploy (pull_request) Has been cancelled
6b1dac5e2b
Gilles changed target branch from feat/23-metric-thresholds to master 2026-10-28 22:53:31 +00:00
Merge remote-tracking branch 'origin/master' into feat/21-org-global-rules
All checks were successful
ci / test (pull_request) Successful in 3m22s
ci / e2e (pull_request) Has been skipped
ci / docker (pull_request) Has been skipped
ci / deploy (pull_request) Has been skipped
d5d9d96a58
# Conflicts:
#	README.md
#	e2e/features.catalog.yaml
Gilles scheduled this pull request to auto merge when all checks succeed 2026-10-28 22:54:34 +00:00
Gilles merged commit d2be0f3147 into master 2026-10-28 23:01:01 +00:00
Gilles deleted branch feat/21-org-global-rules 2026-10-28 23:01:01 +00:00
Sign in to join this conversation.
No description provided.