• v0.8.1 d7c48b06ee

    Notify Bridge 0.8.1
    Release / test-backend (push) Successful in 2m1s
    Release / release (push) Successful in 2m3s
    Stable

    alexei.dolgolyov released this 2026-05-16 18:33:41 +03:00 | 10 commits to master since this release

    v0.8.1 (2026-05-16)

    ⚠️ Breaking Changes

    • Telegram webhook secret is now mandatory. NOTIFY_BRIDGE_TELEGRAM_WEBHOOK_SECRET must be set when running Telegram bots in webhook mode — the inbound endpoint returns 401 without it. Polling-mode bots are unaffected (10d30fc)
    • Generic webhooks with auth_mode="none" require explicit opt-in. Existing unauthenticated webhook providers must set acknowledge_unauthenticated=true in their config or they will be rejected. Generic webhook ingest is also rate-limited to 60 requests/min per source IP (10d30fc)
    • Every user now gets a bridge_self provider auto-seeded. It is internal-only and excluded from the "create provider" wizard, but appears in the provider list. Wire it to a Telegram/Email/Matrix target to receive bridge health alerts (10d30fc)

    User-facing changes

    Features

    • Home Assistant provider. New service provider that subscribes to a Home Assistant instance over WebSocket (long-lived connection with auth handshake, exponential-backoff reconnect, area-registry enrichment) and emits 4 event types: state_changed, automation_triggered, call_service, event_fired. Trackers support entity-glob, domain-allowlist, and exact-id filters via the new TagInput UI control (22127e2)
    • Home Assistant bot commands. /status, /entities [glob], /state <entity_id>, /areas — query your HA instance from chat. Multi-command WS sessions reuse a single handshake; sensitive attributes (camera access tokens, entity pictures, etc.) are blocklisted and /state output is capped at 30 attributes to stay within Telegram message limits (22127e2)
    • Bridge self-monitoring (bridge_self provider). A new internal provider type emits health events from the bridge itself: bridge_self_poll_failures (consecutive tracker poll failures), bridge_self_deferred_backlog (pending defers above threshold), bridge_self_target_failures (consecutive 5xx/network failures per target). Per-user thresholds default to 3 / 100 / 5 and are configurable. Self-loop guard ensures bridge_self failures never count toward target-failure thresholds (10d30fc)
    • bridge_self bot commands. /status, /thresholds, /reset, /health let operators inspect bridge health and reset counters from chat. Includes Jinja2 templates for both locales (8651767)
    • On-watch stats scope selector. New icon toggle on the "On watch" provider deck switches between page-scoped stats (legacy) and full-corpus stats that aggregate across every event matching the active filters (dec0839)

    Bug Fixes

    • Immich periodic summary now honors periodic_interval_days. A configured 3-day interval was firing every day because the dispatch path never consulted the interval or start date. The scheduler now gates on (today - start_date).days % interval == 0 and logs interval_not_due skips so operators can distinguish suppressed-by-interval from other skip causes (90f958b)
    • Planka webhook crash fixed. The handler had a NameError on every call when reading the request body — webhook ingest from Planka now works (10d30fc)
    • HA quiet-hours dropped events. ha_state_changed, automation_triggered, service_called, and event_fired were missing from the deferrable set and were silently dropped during quiet windows. They now defer like every other event type (10d30fc)
    • Notifier no longer cancels peer sends on a single failure. Switched the per-receiver fan-out to asyncio.gather(return_exceptions=True); one bad chat won't cancel sends to the rest (10d30fc)
    • Quiet-hours gate now respects event-type-disabled. When a tracker has the event type disabled, that wins over the deferral path — events are dropped, not stored to be drained later (10d30fc)
    • NUT first poll seeds silently. No more spurious ups_on_battery notification on the very first poll after adding a NUT provider (10d30fc)
    • HA disconnect/reconnect now logged. Status changes write ha_status_* rows to the EventLog so operators can see WS supervisor health in the UI (10d30fc)

    Performance

    • Jinja2 template compilation cached with lru_cache(maxsize=512) — repeated renders of the same template no longer reparse the source (10d30fc)
    • Per-locale render cache in NotificationDispatcher skips re-rendering identical content for receivers sharing a locale (10d30fc)
    • Tracker list cached per provider_id with a 5s TTL plus explicit invalidation on tracker CRUD — relieves the HA chat-bus rate-query pressure (10d30fc)
    • Nav-counts collapsed from 16 round-trips to a single UNION ALL (10d30fc)
    • HA event_log skips empty eventsassets_added/assets_removed events with empty payloads are no longer persisted (10d30fc)

    Security

    • DNS-rebinding SSRF protection. PinnedResolver is now wired into the shared aiohttp session — outbound URL validation pins the resolved IP for the lifetime of the request (10d30fc)
    • Mass-assignment guards added on Action create/update; cron expressions with sub-minute granularity are rejected (10d30fc)
    • Backup import hardening. JSON depth capped at 10, node count at 100k; _sanitize_config now extends to all JSON-typed fields on import (10d30fc)
    • Telegram _safe_get walks redirects manually with SSRF revalidation at every hop (10d30fc)
    • Bcrypt 72-byte password length cap with a clear 422 response (was silently truncating before) (10d30fc)
    • Webhook payload body redaction. Sensitive substring set extended with oauth, client_secret, webhook_secret, csrf in both header filter and template-extras filter (10d30fc)

    Operations

    • Deep healthcheck at /api/ready — checks DB SELECT 1, scheduler running, HA supervisor presence; returns {ready, checks, errors, version} (10d30fc)
    • Prometheus metrics at /api/metricsdeferred_pending, event_log_total, dispatch_duration, poll_failures, send_failures (10d30fc)
    • New OPERATIONS.md covering deploy, healthchecks, metrics, backup/restore procedures, log handling, common scenarios, and upgrade flow (10d30fc)

    Development / Internal

    Architecture

    • Shared dispatch pipeline. Extracted webhook ingest's event-log + deferred-dispatch + quiet-hours code path from api/webhooks.py into services/event_dispatch.py so HA subscription and webhook ingest now share the same pipeline (22127e2)
    • ServiceProvider ABC gains optional subscribe() for push-style providers; HomeAssistantServiceProvider uses it via a per-provider supervisor task started in the FastAPI lifespan (22127e2)
    • Provider construction switched from if/elif ladder to factory registry (10d30fc)
    • Provider credential resolution unified across all 5 dispatch sites (10d30fc)
    • NotificationDispatcher hoisted out of the per-tracker loop (10d30fc)

    Database

    • New UNIQUE indexes: service_provider.webhook_token, telegram_bot.webhook_path_id, partial UNIQUE on telegram_bot.bot_id, telegram_chat(bot_id, chat_id), notification_tracker_target unique link, partial UNIQUE on bridge_self provider per user (10d30fc)
    • Composite ix_event_log_user_event_type_created index (10d30fc)
    • save_chat_from_webhook switched to ON CONFLICT DO UPDATE (was racy under concurrent webhook delivery) (10d30fc)
    • ondelete=CASCADE on user-id FKs (model annotation; app-side cascade delete added for existing data) (10d30fc)
    • delete_notification_tracker converted from N+1 to bulk DELETE/UPDATE (10d30fc)
    • Module-level asyncio.Lock replaced with lazy _get_lock() pattern (avoids cross-event-loop binding) (10d30fc)
    • VACUUM INTO snapshot now PRAGMA integrity_check-verified before being returned (10d30fc)
    • Batched receivers/chats/bots in load_link_data (was per-target N+1) (10d30fc)
    • flag_modified on JSON column reassignments in deferred_dispatch (10d30fc)

    Frontend

    • 76 catch (err: any) sites converted to errMsg(err) helper (10d30fc)
    • globalProviderFilter made a pure getter; reconciliation moved to a one-time $effect in +layout (10d30fc)
    • Provider-filter binding simplified — paired $effects and the _syncingFilter flag removed; now a one-way derived value (10d30fc)
    • entity-cache got a separate _refreshing flag for background re-fetches so loading spinners don't appear on revalidation (10d30fc)
    • api.ts 401 handling rewritten: AuthRedirectError class + dedup _redirecting flag, goto() instead of window.location.href (10d30fc)
    • Accessibility: aria-expanded on mobile More menu, role=switch + aria-checked on Telegram bot toggles (10d30fc)
    • Provider-specific hardcoding removed: Immich-only block extracted to descriptor featureDiscoveryHint (10d30fc)
    • 5 svelte-check null-narrowing errors fixed in EventDetailModal (10d30fc)
    • New TagInput component for free-text glob/domain lists; new toggle ConfigField type for HA descriptor (22127e2)

    CI/Build

    • CI pytest gate added to .gitea/workflows/build.yml and release.yml (wheel-built install to dodge editable-install slowness on the hosted runner) (10d30fc)

    Tests

    • New test suites: test_bridge_self (11), test_gitea_parser (9), test_planka_parser (6), test_immich_change_detector (6), test_backup_roundtrip (1) (10d30fc)

    Other

    • command_sync snapshot+expunge bot before exiting AsyncSession (was raising on detached-instance access) (10d30fc)
    • HA asyncio.shield now drains inner task on cancellation (was leaking tasks on supervisor restart) (10d30fc)
    • APScheduler drain job ID resolution upgraded to seconds (was minute-bucketed; collisions possible) (10d30fc)
    • Webhook payload rollback failures now logged (were swallowed) (10d30fc)

    All Commits
    Hash Message Author
    8651767 feat: bridge_self bot commands — status, thresholds, reset, health alexei.dolgolyov
    10d30fc feat: production readiness — security, perf, bug fixes, bridge self-monitoring alexei.dolgolyov
    22127e2 feat: Home Assistant provider — WebSocket subscription + bot commands alexei.dolgolyov
    90f958b fix(server): honor periodic_interval_days for Immich periodic summary alexei.dolgolyov
    dec0839 feat: on-watch stats scope selector (page vs all) alexei.dolgolyov

    Changelog

    d7c48b0 ci: isolate test backend install in venv
    66f152e fix(tests): green pytest gate for v0.8.1
    faaaa39 chore: release v0.8.1
    8651767 feat: bridge_self bot commands — status, thresholds, reset, health
    10d30fc feat: production readiness — security, perf, bug fixes, bridge self-monitoring
    22127e2 feat: Home Assistant provider — WebSocket subscription + bot commands
    90f958b fix(server): honor periodic_interval_days for Immich periodic summary
    dec0839 feat: on-watch stats scope selector (page vs all)

    Downloads