Skip to content

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning. Releases prior to v1.1.x use the legacy ## VERSION (DATE) heading style.

[Unreleased]

Added

  • Generate outgoing notifications from a maintenance or outage: "Generate Notifications" in the event's Operations menu (with preview), POST /api/plugins/notices/{maintenance,outage}/{id}/generate-notifications/ (with dry_run), and opt-in automatic generation via auto_generate_notifications.
  • Regeneration re-renders untouched drafts in place and keeps hand-edited drafts and anything already approved or sent. Notifications created by hand are never touched by generation.
  • Generation enforces NetBox object-level permissions: a UI or API run that would create, update or delete a notification the user may not add, change or delete is refused and rolled back as a whole.
  • "Reset to template" for hand-edited drafts (UI and POST .../prepared-notifications/{id}/reset/), and "Approve" in the UI.
  • Prepared notifications record their recipient group (tenant, impact) and expose a modified flag, filterable in the list and API.
  • Outgoing notifications appear on the event timeline.

Changed

  • Template matching: every non-base template is an independent notification kind; a template that extends a non-base template overrides it for the recipient groups its scopes match. Fields merge only along the extends chain instead of across every matching template. {% extends "base" %} now renders with the full context and resolves to the template's own parent.
  • An override must use the same granularity as the template it extends, and extends cycles are rejected on save.
  • Maintenance and Outage gain a notifications generic relation to EventNotification, mirroring impacts. No migration is required. Deleting a maintenance or outage now also deletes its event notifications, as it already did its impacts, and the delete confirmation page lists them among the objects that will be removed; previously they were left orphaned with a dangling event reference.

Fixed

  • The maintenance and outage REST API responses never included the event's impacts or notifications: both serializer fields pointed at reverse accessors that do not exist on these models, so DRF silently dropped them. Both keys now return the nested list of linked impacts and received notifications, and the list endpoints prefetch them so response time does not grow a query per event. (#61)

Security

  • Notification templates now render in Jinja's sandbox (SandboxedEnvironment): attributes whose names start with an underscore and data-modifying callables such as save() or delete() are blocked, and a blocked call or lookup fails the render. See the Sandbox section of the templates documentation.

[1.3.0] - 2026-09-12

Added

  • NetBox 4.7 support: CI now tests against NetBox 4.7.0 alongside 4.5.x and 4.6.x, and the README compatibility matrix lists the new series.

Fixed

  • The iCal feed returned 304 Not Modified for any request carrying an If-Modified-Since header, without comparing the date, so calendar clients that revalidate by date -- Apple Calendar among them -- imported the feed once and never saw another change. Conditional requests now go through Django's get_conditional_response, which parses and compares the date, ignores an unparseable one, and gives If-None-Match precedence when both headers are sent, per RFC 9110 section 13.1.3.
  • The iCal feed's ETag was an unquoted hex string, which RFC 9110 parsers discard, so clients and proxies that parse the tag (rather than echo it byte-for-byte) could never revalidate. The tag is now a quoted entity-tag, and weak (W/"..."), comma-listed and * forms match. Tags cached before the upgrade no longer match, so each ETag-only client re-downloads the feed once and then revalidates normally.
  • The iCal feed's Last-Modified could move backwards when a maintenance was deleted or aged out of the past_days window, pinning date-revalidating clients on 304 while the deleted event stayed on their calendars. The validator now also considers the latest logged deletion of a maintenance or impact and the latest window exit, so it never regresses when the feed body changed (#70).
  • One maintenance row with a NULL last_updated (fixture loads, restores, raw SQL) blanked the feed's Last-Modified and froze the ETag's modified component. The validator now aggregates with Max, which ignores NULLs (#71).
  • Impact and provider changes are rendered into the feed body (DESCRIPTION, LOCATION) but moved neither validator, so revalidating clients received 304 for a changed feed. Both validators now cover the matching maintenances' impacts and providers, and the ETag additionally hashes the impact count (#73).

  • The documentation site rendered {% include-markdown "../README.md" %} as literal text on the home page, changelog, contributing and AWS SES pages. That macro comes from mkdocs-include-markdown-plugin, which Zensical does not load; those four pages now use pymdownx.snippets instead.

  • README screenshots and its permissions link used repo-relative paths, so they 404'd on the documentation site and on PyPI. They are absolute URLs now.
  • Eight pages referenced by the documentation nav were never written, so the sidebar linked to .md URLs that 404'd, along with six cross-page links. Written: the REST API reference, the developer guide (architecture, resolvers, template extensions), the messaging guide (templates, recipient discovery, approval workflow) and the dashboard page.
  • outgoing-notifications.md documented models under names they have never had (MessageTemplate, PreparedMessage) and its integration examples used a prepared-messages/ endpoint that does not exist and a ready to delivered transition the state machine rejects. It is now an overview over the three messaging pages, with corrected examples.

[1.2.0] - 2026-08-31

Fixed

  • Bulk edit, bulk delete, import and add buttons navigated to .../None (#56). Every list view -- and the two detail views that inherited actions with no URL -- now declares an explicit actions tuple; 18 buttons across 8 views.
  • The Sent Notifications list 500'd as soon as it had one row: its table kept ActionsColumn's default edit/delete set, which the proxy has no URLs for.
  • Prepared Notification status was settable from the UI, skipping the transition's side effects. It is now REST-API-only (PATCH /api/plugins/notices/prepared-notifications/<id>/) and the bulk edit view is unmounted.
  • /plugins/notices/impact/<pk>/changelog/ 500'd: Impact has no list or detail view, so the breadcrumb could not resolve. Its changelog and journal tabs are unmounted -- impact changes still appear in the parent event's changelog.
  • The received-notification detail page and its tabs rendered as a bare unstyled fragment; eventnotification.html now extends generic/object.html.
  • Impact.get_absolute_url() raised NoReverseMatch for an impact whose event row was deleted out of band, 500ing any list rendering it. It now falls back to the parent type's list.
  • PreparedNotification.headers and .recipients had JSONField defaults that failed full_clean(). Migration 0011 adds blank=True -- validation only, no data change.
  • A POST to the prepared notifications API could create a record directly in ready, skipping the state machine's recipient snapshot and its "no recipients" guard. Since ready has no transition back to draft, the outbound poller then retried the record forever. A create must now use draft; later states are reached with a PATCH.
  • Sanitized email HTML kept its class attributes, which on a full NetBox page are live Tabler utilities -- a provider could float its email over the surrounding UI as a clickable overlay. sanitize_html now drops class.

Added

  • Bulk edit for Maintenance, Outage and Notification Templates. status and the scheduling fields are excluded -- the transition and reschedule views own them, and Outage.clean() requires an end when RESOLVED.
  • Bulk delete for Maintenance, Outage and Notification Templates. Received notifications (raw MIME in a BinaryField) and sent notifications (a proxy, so deletes would bypass PROTECTION_RULES) are excluded; both stay deletable elsewhere -- see PERMISSIONS.md.
  • Journal tab on every detail page, plus a Changelog tab for received notifications, from NetBox's automatic feature-view registration. Impact is excluded -- it has no detail page (see Fixed).
  • Bulk import (CSV/JSON/YAML) for Maintenance and Outage. Impacts are a child relation and are not imported.
  • Canonical normalize-toolkit CI/CD shape: 5 GHA workflows (ci.yml, publish.yml, docs.yml, release-drafter.yml, pr-title.yml) + .github/release-drafter.yml. Replaces the previous mkdocs.yml workflow.
  • Local commit-msg pre-commit stage that rejects AI/Claude attribution lines.
  • .git-template/hooks/commit-msg -- canonical hook tracked in-tree, referenced by pre-commit.
  • docs/zensical.toml -- migrated from mkdocs-material to zensical (matches the toolkit canonical).
  • uv.lock committed for reproducible CI/dev environments.

Changed

  • notices/urls.py rewritten to NetBox 4.x's @register_model_view / get_model_urls() pattern. Every URL name and path is unchanged except the deliberately unmounted ones (see Fixed); tests/test_url_patterns.py pins the rest.
  • The sent notifications changelog now resolves against SentNotification, so it 404s for a draft's pk instead of rendering it -- matching the detail view.
  • CI: switched dependency installation to uv for faster caching; activates the workspace .venv via GITHUB_PATH so plain python works from /tmp/netbox/netbox. Codecov upload uses OIDC (tokenless), gated to a single matrix leg.
  • publish.yml: switched build/publish jobs to uv build (was python -m build); pinned actions/upload-artifact and actions/download-artifact to v4 (matches canonical).
  • pyproject.toml: dropped black, isort, flake8, pyproject-flake8, pip-tools, twine, Sphinx, watchdog, tox from dev deps -- all superseded by ruff or moved to per-step CI installs. Removed legacy [tool.flake8] and [tool.tox] sections. Added [docs] extra (zensical). Expanded ruff selectors with N, UP, S, B, A, DJ, PIE. Several pre-existing issues (B904, S701, S324, S308, A004, DJ001) are temporarily globally ignored -- see TODO comment in [tool.ruff.lint]. Test per-file ignores added for E402, F841, B011. Added extend-exclude for migrations/ and parsers/. Added bumpver CHANGELOG.md file pattern so the Unreleased section is promoted on every version bump.
  • mkdocs.yml (root) and .github/workflows/mkdocs.yml removed -- replaced by docs/zensical.toml + .github/workflows/docs.yml.
  • README trimmed from 542 lines to ~95 -- substantive content now lives in the published docs site.
  • CI test matrix now covers the newest release of each supported NetBox series -- 4.5.10 and 4.6.9 -- against Python 3.12, 3.13 and 3.14. NetBox 4.5.8 is dropped; 4.6.x is covered for the first time. Renovate keeps each matrix entry pinned inside its own minor series, and the test job gained a 30-minute timeout.
  • tests/test_ical_download.py and tests/test_ical_view.py run in CI again. They were excluded when the workflow was first written against NetBox 4.4; the rewritten suites finish in about 18 seconds. The workflow's NetBox configuration now also defines API_TOKEN_PEPPERS -- NetBox refuses to save a v2 API token without one, and its own configuration_testing.py supplies it, so the v2 token test passed locally but failed in CI.
  • Documented requirements corrected: docs/installation.md listed Python 3.10 and 3.11, which NetBox 4.5+ has never supported (the package already requires 3.12+). README's install section said NetBox 4.5.2+ where the rest of the page says 4.5.0+.

1.0.0 (2026-02-09)

New Features

  • Outgoing Notifications: New notification system for customer/stakeholder communication
  • NotificationTemplate model with Jinja templating support
  • Template scoping (similar to Config Contexts) for tenant/provider/site-specific templates
  • Template inheritance for customization
  • PreparedNotification model with approval workflow (draft -> ready -> sent -> delivered/failed)
  • SentNotification proxy model for viewing sent/delivered notifications
  • Recipient discovery based on contact roles and priorities
  • iCal attachment support for maintenance notifications
  • AWS SES Integration (integrations/aws-ses/): Complete AWS SAM application for email delivery
  • Inbound Lambda -- SES receipt rule -> S3 -> parse with circuit-maintenance-parser -> NetBox API
  • Outbound Lambda -- Poll NetBox for ready notifications -> build MIME -> send via SES
  • Tracking Lambda -- SES delivery events (delivery, bounce, complaint, open, click) via SNS -> NetBox status updates
  • Webhook support via API Gateway for immediate delivery on status change (alternative to polling)
  • Polling and webhook modes independently toggleable (can use either or both)
  • Optional VPC deployment for Lambda functions (private subnets with NAT Gateway)
  • SES Configuration Set with full event tracking (send, delivery, bounce, complaint, open, click)
  • HMAC-SHA512 webhook signature verification for NetBox Event Rules
  • Comprehensive documentation: architecture, quick start, email authentication (SPF, DKIM, DMARC)
  • Developer Tooling: Plugin demo data loader and netbox-demo-data toolkit integration

API Changes

  • New endpoints for notification management:
  • /api/plugins/notices/notification-templates/ - CRUD for notification templates
  • /api/plugins/notices/prepared-notifications/ - CRUD with status workflow
  • /api/plugins/notices/sent-notifications/ - Read-only view of sent notifications
  • Status transitions support optional timestamp and message fields

UI Changes

  • Renamed "Inbound" menu item to "Received" for clarity
  • New "Sent" menu item for viewing sent/delivered notifications
  • New "Notification Templates" management UI
  • New "Prepared Notifications" management UI with approval workflow

Documentation

  • AWS SES integration guide with architecture diagrams and deployment instructions
  • Outgoing notifications documentation with Slack and SES integration examples
  • Email authentication guide (SPF, DKIM, DMARC, Custom MAIL FROM)
  • Updated parsers documentation with SES cross-references

0.1.0 (2025-11-18)

BREAKING CHANGE: Complete refactor from netbox-circuitmaintenance to netbox-notices

This is the initial release of the fully refactored plugin, now supporting both maintenance and outage tracking across multiple NetBox object types.

New Features

  • Outage Tracking: New Outage model for unplanned outages with automatic timestamps
  • Generic Impact Tracking: Associate impacts with any NetBox object (circuits, devices, VMs, etc.)
  • Reschedule Functionality: Reschedule maintenance events with automatic status updates
  • Timeline View: Visual timeline of all changes and events
  • Choice Constants: All ChoiceSet classes now define constants (STATUS_, IMPACT_)
  • Impact Field: Added impact text field to BaseEvent for describing event impact
  • Reported At: Outage model includes reported_at timestamp with timezone conversion
  • Timezone Support: Automatic timezone conversion and display for all timestamp fields
  • Changelog Tracking: Proper changelog tracking for reschedule operations and related objects
  • PyPI Publishing: Automated GitHub Actions workflow for PyPI releases

API Changes

  • REST API support for Maintenance and Outage models
  • API serializers include all new fields (impact, reported_at, replaces)

Infrastructure

  • NetBox 4.4.1+ compatibility
  • Python 3.10+ required
  • Automated CI/CD with GitHub Actions
  • MkDocs documentation with GitHub Pages deployment

Migration Notes

This is a completely new plugin architecture. Previous versions (0.6.0 and earlier as netbox-circuitmaintenance) are not compatible.


Historical Releases (netbox-circuitmaintenance)

0.6.0 (2025-09-08)

  • Netbox 4.4 support
  • Bug fix by @PetrVoronov
  • Highlight current date in calendar event view

0.5.0 (2025-06-02)

  • Netbox 4.2 support

0.4.2 (2024-09-29)

  • Adding Maintenance calendar widget
  • Fix #26 - f string quote issue with NB 4.1

0.4.1 (2024-09-19)

  • Adding Maintenance Schedule calendar

0.4.0 (2024-09-19)

  • Adds support for Netbox 4.0 and 4.1
  • Adds widget to show circuit maintenance events
  • Updates styling to match new Netbox style

0.3.0 (2023-04-28)

  • Fixed support for Netbox 3.5. NOTE: Plugin version 0.3.0+ is only compatible with Netbox 3.5+

0.2.2 (2023-01-18)

  • Fix API Filtersets
  • Viewing notification content opens a new tab
  • Updating RESCHEDULED to RE-SCHEDULED to match circuitparser

0.2.1 (2023-01-17)

  • Updating to DynamicModelChoiceField
  • Hiding maintenance schedule for now

0.1.0 (2023-01-15)

  • First release on PyPI.