Skip to content

Changelog

All notable changes to netbox-kea-ng are documented in this file.

This project follows Conventional Commits and uses Semantic Versioning. python-semantic-release writes every entry below from the commits on main and inserts each new release directly under the marker, so nothing here is edited by hand.

Entries for v1.0.4 and earlier are empty. They are the release tags of devon-mar/netbox-kea, which this project forked, and predate its conventional-commit history.

v3.8.1 (2026-10-22)

Bug Fixes

  • deps: Bump the uv group across 1 directory with 2 updates (#154, 540fd92)

v3.8.0 (2026-10-20)

Bug Fixes

  • options: Keep csv-format when an option row replaces its data (80b0104)

  • options: Refuse an added or changed DHCP Option whose identity another entry holds (cb1d513)

Testing

  • options: Use hexadecimal data where csv-format is false (7027533)

v3.7.0 (2026-10-18)

Bug Fixes

  • Build every Kea failure text with kea_error_message (ceedada)

  • Classify raw TLS reply failures as unknown (06ce765)

  • Give unknown for every TLS failure of a command (5971e15)

  • Name DHCP import failure families and align diagnostic tests (3788ffb)

  • Preserve Kea reply text in unsupported-command and unreachable-daemon errors (103e5d2)

  • Reject a change that Kea answers with result 2 (65015fb)

  • Reject a change that never reached Kea's command handler (2d309b6)

  • Show a stopped DHCP service and a changed target as warnings (6f05907)

  • Stop a loop of changes when the Kea client cannot be built (a6e0429)

  • Treat only proof that Kea did not run a command as not sent (fe1912d)

  • config: Treat a config-test that cannot reach the daemon as not sent (ebc11eb)

  • kea: Check the reply envelope of a Lease write before its result (75e96be)

  • kea: Never follow a redirect for a Kea command (d7916c2)

  • kea: Report credentials that requests cannot encode as a request error (72cf485)

  • kea: Treat an encode failure after the send as a request error that can have reached Kea (b39a726)

  • leases: Keep the Line and Address columns of the import report narrow (b94ef46)

  • leases: List each row of a Lease CSV import under its own status (6b88260)

  • leases: Report an applied Lease add when its sync events fail (4c50ebf)

  • leases: Send lease_added for an imported row before the next row goes to Kea (0811ee2)

  • opengrep: Limit the reported dispatch error to the IPAM sync after a Runtime Change (533a6b4)

  • reservations: Apply the review findings of the Configuration Change move (88c397a)

  • reservations: Send Reservation writes as Configuration Changes (a927981)

  • views: Run the view read ladders through load_snapshot and load_target (f9f34f1)

  • views: Show the Catalogue Notice when a Reservation load cannot confirm its Subnet (997c2fc)

Chores

  • deps: Bump pydantic from 2.13.5 to 2.14.1 (f37bb6b)

  • deps: Bump the github-actions group with 4 updates (e02c953)

  • deps-dev: Bump markdown-it-py from 4.0.0 to 4.2.0 (7ea04dd)

  • deps-dev: Bump pytest-playwright from 0.9.0 to 0.10.0 (58ac0eb)

  • deps-dev: Bump ruff from 0.16.10 to 0.17.0 (91ecc1c)

  • opengrep: Refuse a Kea read ladder in a view (01179f0)

  • opengrep: Refuse a Reservation write primitive outside config_write (4d8a900)

  • opengrep: Require a raise or messages.error() in a dispatch-error clause (2a41aca)

Continuous Integration

  • opengrep: Check migrations for a Runtime Change write (362045b)

  • opengrep: Refuse a Runtime Change write outside runtime_change (c959422)

Documentation

  • Clarify that Kea result 2 may indicate a missing hook library (d4180ae)

  • Describe failed_load and the credential encoding error (7ac6f17)

  • Describe load_target and the Kea line of a failed read (3c2f0b9)

  • Describe Reservation writes as Configuration Changes (3a5f3b2)

  • Record the DHCP Import parity decisions (a1bb5ad)

  • adr: List every failure that means a Configuration Change was not sent (943b67e)

  • design: Describe the Lease update after the Runtime Change move (f77b3c4)

  • design: Say that a Lease edit compares the fresh Lease with the shown facts (46d3cee)

  • guide: Say that a delete or an import stops when the client cannot be built (591399e)

  • signals: State when a Lease CSV import stops (179a3d2)

Features

  • Send Runtime Changes through runtime_change (ef12a50)

  • Show Kea's own reply text through one formatter (cd4b0ac)

Refactoring

  • Give mutate an explicit failure policy (f8f98c7)

  • Move the change classifier into change_outcome (170fc46)

  • leases: Take a list of addresses in _add_lease_journal (a5bc2c4)

  • views: Share the journal and signal helpers of an applied change (56db04a)

Testing

  • Accept the HTTPError that KeaClient.command builds for a redirect (1a164b8)

  • Allow TLS exception types at the client boundary (7cd69cb)

  • Assert the unconfirmed lease delete report (d330f9c)

  • Gate the DHCP integration regression on its real dependency (3d678a5)

  • Keep the broken TLS record ahead of the close in the stub server (771f3f4)

  • Make the self-signed TLS certificate with cryptography (b0894bf)

  • Pin that a Kea command is never retried (466012b)

  • Pin the separate error of a failed side effect after an applied change (98721a1)

  • Refuse TLS versions before 1.2 in the stub TLS server (77ac3a7)

  • ui: Expect the CSV import to stop at the row that Kea did not confirm (375073a)

v3.6.2 (2026-10-17)

Bug Fixes

  • plugin: Show the fork name and author in the Plugins table (52feb6e)

Documentation

  • Use unknown for an outcome that Kea did not confirm (3792caf)

  • adr: Classify a failed Lease wipe as unknown (388f9bc)

  • adr: Give unknown for a failed Lease write and define side-effect errors (ab068a3)

  • adr: Give unknown for a failed Reservation write (686a610)

  • adr: Give unknown for every TLS failure of a command (3571132)

  • adr: Narrow the not-sent rule to answers that Kea never ran (52302ae)

  • adr: Read a Lease again after a failed Lease write (4f2862a)

  • adr: Record Runtime Changes and Reservation writes as typed changes (e062600)

  • adr: Reject a change that Kea did not run (6f8304b)

v3.6.1 (2026-10-16)

Bug Fixes

  • leases: Refuse a Kea lease with a scoped IPv6 address (b3e3557)

  • leases: Show the Lease Synchronization State from the ownership read (097c426)

  • reservations: Build the Row Sync badge from the ownership read (1e4ba93)

  • reservations: Keep a Row Sync result when the ownership read fails (2e6d80e)

  • reservations: Read the Reservation sync state from the ownership links (168fe39)

  • reservations: Return no advisory when the ownership read fails (9aa6d14)

Chores

  • opengrep: Refuse a Prefix ownership read in a view without a DatabaseError handler (c654cae)

  • opengrep: Refuse an ownership read in a view without a DatabaseError handler (1ca34d5)

Code Style

  • leases: Keep a gap between the state badge and Sync when the cell wraps (34b604e)

Documentation

  • context: Define ownership of the Reservation and Lease Synchronization States (293d5b3)

Refactoring

  • ipam: Read the ownership of a Prefix with the rules of an IP address (f54bb6d)

  • ipam: Take the ownership link field from the model and pin the Lease state labels (2d47d57)

  • reservations: Name the ownership states after CONTEXT.md (7c4cf80)

v3.6.0 (2026-10-15)

Bug Fixes

  • leases: Raise a new failure object for each Lease that needs a failed lookup (6c4d48d)

Chores

Testing

  • leases: Read the Kea reply of each Global Reservation subtest (7a3637d)

v3.5.0 (2026-10-14)

Bug Fixes

  • reservations: Leave the Lease badges unknown when the settings read for them fails (b931d4e)

Performance Improvements

  • dhcp-plugin: Read the integration switch once on the DHCP plugin page (b044e57)

Testing

  • Wait for TomSelect's filter refresh before the filtered Attribute pick (3db87d2)

v3.4.0 (2026-10-13)

Bug Fixes

  • fan-out: Read the Kea client settings once on the request thread (f572ee1)

  • settings: Check the 0018 switches and keep each test's settings (4f5f7cf)

Documentation

  • settings: Name the Settings page as the home of every runtime setting (3f75f58)

Features

  • settings: Move the PLUGINS_CONFIG runtime keys into Settings singletons (d5777d6)

v3.3.0 (2026-10-13)

Bug Fixes

  • api: Give KeaDhcpLink a brief serializer for the change log API (6945ff8)

  • cache: Key display Snapshots by the Server connection settings (df270bf)

  • catalogue: Treat a CIDR or address as absent only when both sources agree (a1640c2)

  • reservations: Match a hook by its library name, not by its path (0d96d0b)

Documentation

  • settings: Clarify that saving Sync Configuration requires view and change permissions (e84146b)

Features

  • settings: Add a Settings page with the change-logged SyncConfig form (f90bbc0)

Refactoring

  • config: Read Reservation capabilities and the Lease search Subnet through one config-get authority (649252e)

Testing

  • cache: Cover the display cache after a Server change through each path (713d263)

  • settings: Require the Settings menu item for a viewer of any section (866d3d1)

v3.2.0 (2026-10-12)

Bug Fixes

  • Keep a one-Server export on the combined view (12f30c9)

  • Keep an empty Server selection explicit and keep the section filters on Apply (dfeda9a)

  • Let the Server selector apply several Servers and keep exports on redirect (ed1d9d2)

  • Read the last value of a repeated lease search field on the chooser (5601edc)

  • Refuse a combined export when a selected Server lacks the family (3f0d72b)

  • Stack the invalid Server selection text in its alert (210a938)

  • ci: Collect plugin static files in the integration harness (2af6927)

  • types: Annotate the shared Reservation form helpers (f6859fa)

  • ui: Build export refusal redirects from named routes (39baf6b)

  • ui: Disable the lease Search value during an Attribute change (f86d1a9)

  • ui: Drop the CIDR example from the Subnet dropdown help (9339124)

  • ui: Keep exhausted Servers in the All Servers Subnet ID choices (0baab1c)

  • ui: Keep Lease search controls stable during submit (99c500c)

  • ui: Keep the URL when a lease search does not change it (0de0f5f)

  • ui: Label unlisted Subnets "not listed" and show Catalogue warnings (c1d7f4c)

  • ui: Move the Add Lease IPAM sync notice into the checkbox help (0994ab2)

  • ui: Report a failed Catalogue in the All Servers Subnet ID choices (298afd1)

  • ui: Show the code markup in the Subnet edit help (9985c54)

  • ui: Space the Recent Runs header link with flex (05a7bfb)

  • ui: Wrap card header badges below the title on narrow screens (ac003c5)

  • ui: Wrap long Server names in the workspace (8d59694)

  • workspace: Keep the origin on Overview status controls (218e3fa)

  • workspace: Preserve chooser origin and align CI guards (3ce1a4e)

  • workspace: Retain list queries in row action returns (80bae63)

Documentation

  • Drop remote-id from the Reservation identifier types (1c14f61)

  • adr: Cache display reads and move runtime settings to the database (568d6e0)

  • adr: Say that a stale entry shows until the first read after its TTL (7c46dad)

Features

  • Add the shared combined workspace shell (6a6b2f4)

  • Replace the combined lease search with a Server chooser (5c56aef)

  • Resolve the Server Scope of combined pages in one place (5f15d56)

  • ui: Collapse the DHCP plugin import mapping notes (ecee678)

  • ui: Keep workspace state when switching Servers (ebdd444)

  • ui: Move DHCP Plugin under Sync and native tabs into the main row (ea0de93)

  • ui: Offer Subnet dropdowns and move Reservation form notes into help (2b29811)

  • ui: Retain workspace return paths (e43e56b)

  • ui: Unify Server workspace navigation (0700979)

Testing

  • Export one Server from the combined views again (048415b)

  • Verify chooser filters and local export redirects (980f648)

  • ui: Assert that page 2 sends no Reservation read to an exhausted Server (4be1934)

  • ui: Make two browser tests pass on NetBox 4.3 and after a filtered pick (9ffc7c2)

  • ui: Match the subnet delete link by its path (de4586f)

v3.1.2 (2026-10-11)

Bug Fixes

  • Name client settings errors on Reservation forms (d33560c)

Continuous Integration

  • Skip the Release run that the release commit starts (9e08841)

Documentation

  • Play each recording when the reader scrolls to it (91757fc)

v3.1.1 (2026-10-11)

Bug Fixes

  • Check page media URLs under the site URL in the docs media check (9d0ce04)

  • Read README images with a CommonMark parser in the docs media check (106d282)

Build System

  • deps: Bump actions/upload-artifact (5177216)

Continuous Integration

  • Deploy only the latest release tag to the documentation site (6332b1b)

  • Deploy the documentation site from the release tag after a release (71d1c79)

  • Keep every waiting documentation deployment in the pages queue (694808e)

Documentation

  • Add CI-recorded workflow clips to the documentation site (43219da)

  • Give the Kea Control Agent its real deprecation and removal versions (1cc4666)

  • Remove the last committed screenshot and refuse new ones in pre-commit (01f7aa4)

  • Set the docs harness variant for the setup command only (288900a)

  • State that a manual Sync by grant needs an active user (6a13712)

  • Tell an API client to drop an unusable X-NetBox-Branch header (b83b536)

Testing

  • Delete only the claimed Sync rows and cut each clip from its page (ca4ab1f)

  • Give the edit-lease toast check the request timeout (5015dd1)

  • Record the documentation clips on a harness that persists Kea's configuration (305e593)

v3.1.0 (2026-10-10)

v3.0.0 (2026-10-10)

Bug Fixes

  • A lease does not rewrite the MAC description of a reserved host (35c2241)

  • Check a created Lease against its request and show a Reservation of the other kind (cb91d86)

  • Fail only the claim rows of a Reservation without a known published name (9f17762)

  • Import an addressless Reservation without a known published name (5fc1584)

  • Keep proxy values out of the setup script trace (83ba776)

  • Keep Reservation claims free of Kea reads (eb6af05)

  • Lock the legacy IP during repair and gate lease Sync on its IPAM permissions (76dcaba)

  • Name every source of the qualifying suffix in the Reservation hostname help (3ba83c8)

  • Name the changed lease facts as a list with "and" (156626b)

  • Name the file line of a lease CSV row in import errors (e5e21a3)

  • Open the edit form of an addressless Reservation under a Pool suffix (1eb3cff)

  • Open the Reservation edit form when the DDNS suffix is unknown (8cd906b)

  • Prefill the published name of a lease in its Reserve link (487579d)

  • Refuse a DHCP plugin import without unconstrained DHCP plugin grants (8404997)

  • Reject two statistics rows for one Subnet (9da05b2)

  • Select the Leases tab on the lease import page and show a full example file (aa2c909)

  • Show an unknown qualifying suffix on the hostname field (496d19a)

  • Sync the published name from both the lease and the Reservation source (a72ff57)

  • Take a Pool DDNS qualifying suffix from the Pool of the address (4559ecb)

  • Warn when Kea refuses the Subnet utilization read (2d6b5ce)

  • jobs: Write the traceback of an unhandled server error to the worker log (6923b58)

  • leases: Compare the hostname of a created lease without case (ab653a7)

  • sync: Classify the legacy link of a delegated prefix that is not current (eb771ed)

Build System

  • deps: Bump pydantic from 2.12.5 to 2.13.5 (b65ec3e)

  • deps-dev: Bump ruff from 0.16.9 to 0.16.10 (4ad2d8a)

  • deps-dev: Bump types-requests (80caee0)

Chores

  • Guard the sync against a hostname that is not the published name (31ceb88)

  • Match only a reported hostname in kea-sync-hostname-unpublished (b51ccb0)

  • templates: Remove the orphan dashboard and global templates (3faf8f9)

Documentation

  • Describe the Lease action, creation and signal contract (4362b52)

  • Describe the published name of a Reservation hostname (bd09763)

  • context: Name the Lease hostname as the lease source's IPAM name (923d2ab)

  • ipam: Say why a Global Reservation falls through to its link reports (0d4865f)

Features

  • Add one owner for the name that Kea publishes for a reserved hostname (814a8c2)

  • Check a fresh read before a Lease edit or delete, and create Leases from typed requests (52ce99b)

  • Preview the published name in the Reservation form (666a4d2)

  • Reconcile live delegated-prefix Lease ownership safely (14448c9)

  • Reserve a delegated-prefix Lease as a Reservation prefix (bd748bc)

  • Resolve the effective DDNS qualifying suffix of each Subnet (5779002)

  • Take the published name in the Reservation add and edit forms (e3ac265)

Performance Improvements

  • sync: Skip the lease link classification when no link is unclassified (e265d5d)

Refactoring

  • Address the review notes on the published-name change (738ba9e)

  • Require the catalogue for a Reservation claim (cc1e491)

Testing

  • Check that each sortable htmx table sits inside its container (3901123)

  • Pass the verifying catalogue to the Reservation sync state claims (3aed9d0)

  • Post a hardware address so the lease journal error tests reach the journal (3120413)

  • Record the lease edit and delete replies of a real Kea 3.2 (095a7ba)

  • ipam: Keep a legacy-marked Prefix in a DNS view syncable (05d0639)

  • jobs: Move the unhandled server error test next to the DNS view regression (ca32c6c)

  • stub: Derive the transaction time of a lease add from its expire (32c255b)

Breaking Changes

  • The lease_added signal sends creation (the LeaseRequest that Kea confirmed) and lease (the Lease that the read back observed, or None), instead of ip_address, hw_address and hostname. The leases_deleted signal sends leases (the Lease values whose deletion Kea confirmed) instead of ip_addresses. A refused, changed or failed action sends no signal. The DHCPv4 lease CSV import requires the hw-address column, and the import result shows the row number and the address of each failed row instead of the raw row.

v2.0.0 (2026-10-08)

Bug Fixes

  • Accept only a local path as a return URL (51bb3b7)

  • Bound Subnet ID lease queries to the Kea range (66a2ca5)

  • Check all Reservation MACs before the first MAC write (910f9bc)

  • Check each Reservation MAC once with a bounded query (fcca25c)

  • Close coverage and relationship gaps in Lease reads (4a5d670)

  • Delete a selected delegated-prefix lease as a prefix (4d647d0)

  • Do not link a delegated-prefix lease row to a NetBox IP Address (b87e539)

  • Fail one lease delete on a malformed Kea reply (ce44a99)

  • Hide the background_job label on the lease bulk-delete page (fd68664)

  • Keep a blank lease search query in the return URL (e479069)

  • Keep a Reservation conflict a conflict when its MAC does not resolve (82dd7eb)

  • Make one event write per MAC sync and check Reservation MACs first (7d45edc)

  • Offer lease Sync and Edit only for address leases (83af234)

  • Offer the create-reservation link only for address leases (7b1866e)

  • Parse lease Subnet IDs as ASCII decimal digits only (5b9f157)

  • Refuse lease Subnet IDs above the Kea range before any request (298e9a1)

  • Register each Option Definition view once (8dfc7f1)

  • Render Subnet, Shared Network and Lease page controls in the content block (81d8257)

  • Report a Kea reply body that is not a JSON list as a malformed reply (840f21f)

  • Return 502 for every Kea transport failure on REST lease search (06eedc3)

  • Return 502 for every malformed Kea reply on REST lease search (5107877)

  • Return to the lease search after a lease edit (5f518f5)

  • Return to the search from the Reserve and Add Reservation links (e07628d)

  • Run every caught plugin transaction through event_scope.atomic (b046b5d)

  • Select the Reservations tab on the Reservation import page (f5f6530)

  • Select units from NetBox 4.6.9, where event_tracking first nests (fb2fb0f)

  • Serve the lease CSV import at one URL per family (6ea0120)

  • Show a hostname-only Reservation as a host reservation (efd88f8)

  • Show a readable message for Kea result 4 (9524bc0)

  • Show no empty meta fields box on the lease bulk-delete page (00910e7)

  • Show the prefix length on a delegated-prefix lease row (0acf285)

  • Space header icons and tidy the lease import page (48a1cdf)

Chores

  • Flag a RequestException handler without a RuntimeError sibling (067cb4d)

  • opengrep: Flag Exception and BaseException inside tuple handlers (6fef7d5)

  • opengrep: Guard plugin transactions and NetBox event internals (a214975)

Continuous Integration

  • Run the event-rollback tests on NetBox 4.3 (1850b07)

Documentation

  • Design for queued events of a rolled-back plugin transaction (462566d)

  • Document the Lease observation, REST and CSV contract (7391ec5)

  • List the complete Lease export columns and read edges (4797a3f)

  • Name the unit gate in AGENTS.md without a NetBox patch release (92d83d0)

  • State the NetBox 4.6.9 unit boundary in the design summary (ae1202f)

  • State when event rules see plugin changes, and the known limits (c3abcd9)

Features

  • Add event_scope.atomic as the owner of plugin transactions (36401ae)

  • Read Leases as typed observations in every read consumer (7ceaad1)

Refactoring

  • Catch DatabaseError without its own subclasses (64eef13)

  • Catch only the exceptions that each Kea-adjacent try can raise (25708ab)

Testing

  • Answer lease get-all in the branching guard read stub (9e96255)

  • Assert a lease with a string subnet-id is excluded and diagnosed (8c2911d)

  • Derive the unit gate from the NetBox version, not from event_scope (d5d4c36)

  • Exercise missing and null lease subnet-id before reservation lookup (492f027)

  • Expect the not-found warning when a lease vanishes before delete (7dfe0c6)

  • Give the branching guard lease fixtures that a real Kea sends (e7dd3be)

  • Pin the event limits of a late delete guard and a branch merge (349911d)

  • Remove a prefix Reservation test that pinned a wrong badge (f32b262)

Breaking Changes

  • Export All Leases and All Data use the documented columns family, kind, address, prefix_length, subnet_id, state, current, hostname, valid_lifetime, last_transaction, infinite, expires_at, then hw_address and client_id for DHCPv4, or duid, iaid, hw_address and preferred_lifetime for DHCPv6. A Subnet CIDR search for an unconfigured CIDR is refused instead of returning no leases.

  • The leases4 and leases6 REST actions return a normalized Lease observation: count, results, diagnostics, complete, next_cursor, query, coverage and evaluated_at. Each result is the public Lease projection (family, kind, address, prefix_length, subnet_id, state, current, binding, hostname, valid_lifetime, last_transaction and expiration). The UI-enriched keys, the Kea extension values and the display labels are gone. Lease CSV exports add the Family, Kind and Prefix Length columns and drop the Type, Reserved and NetBox IP columns. Export All Leases and All Data refuse an observation with a malformed record. The Current View export is labeled limited coverage and is named leases_limited_coverage.csv.

v1.14.0 (2026-10-07)

Bug Fixes

  • Resolve branch control targets without the script prefix (fb5175f)

  • Show a pending reservation on a lease, not Reserved (07a46fe)

Continuous Integration

  • Copy the CA bundle into the compose project for the build secret (522ba29)

Documentation

  • Separate the D12 completion note from the snapshot() follow-up (484e969)

  • State that get_client() raises ValueError only (a3b4715)

Testing

  • Count every runtime snapshot in the documented inventory check (2ad984d)

  • Match branching job test paths at a path boundary (bfcb8bc)

  • Reject a compose secret source that expands to an empty path (e0acf7a)

v1.13.0 (2026-10-05)

Bug Fixes

  • A legacy marker kind ends at a word boundary (0a0eeec)

  • A plain OSError from a sync snapshot fails only that phase (b127f39)

  • Align ownership routing and sync VRF guidance (3c0c93c)

  • An unknown stale_ip_cleanup mode fails the old cleanup like the reconciliation (41cd92d)

  • Claim IPAM ownership for per-row sync and lease add (4530703)

  • Clean expired leases when Reservation sync is disabled (3fcf7d6)

  • Cleanup gives an object the hostname of its remaining links (a37afb3)

  • Drop the per-Server unowned count from sync summaries (1432d09)

  • Freeze adoption policy only for final-link cleanup (9264a0c)

  • Handle malformed lease claims and cover reconciliation boundaries (9d2c0f5)

  • Isolate MAC synchronization writes in a savepoint (f77c1d6)

  • KeaClient takes timeout and max_unpaged_leases with no default (7057edb)

  • Keep Server receipts on a forced update (e6b7b4e)

  • Lock ownership links before adoption policy (f5825b1)

  • NetBox refuses to start with an unknown stale_ip_cleanup value (52a1cbd)

  • NetBox validates every netbox_kea setting at startup (4c0f3d6)

  • NetBox validates sync_enabled at startup too (928f3b2)

  • One phase compares its own reports with the owner hostname rule (a7df8f2)

  • Permit ownership checks during receipt completion (f920215)

  • Preserve branch refusals and assert cleanup outcomes (17fe719)

  • Preserve IPAM upgrade receipts and scoped summaries (5b9a323)

  • Preserve network import completion with invalid global options (1b2a98e)

  • Preserve operator notes when claiming IP addresses (eca1ade)

  • Preserve prechange data for plugin updates (#233, 3c43fc2)

  • Preserve shared prefix markers and claimed MAC results (9290c28)

  • Record IPAM sync changes in the changelog (#234, 33dd3e4)

  • Refuse busy cleanup identities in outer transactions (792046b)

  • Refuse busy ownership rows during cleanup (0ee7ad3)

  • Reject malformed lease subnet IDs before reconciliation (9ebd9d3)

  • Release deprecated IP ownership after operator edits (88674c5)

  • Remove obsolete lease mask resolver import (147d12f)

  • Resolve lease ownership facts from the Kea catalogue (c7a91b7)

  • Retain delegated-prefix failure diagnostics (7b41592)

  • Retain every commit's release guidance in changelog (c724167)

  • Serialize adoption cleanup with policy changes (58b5a94)

  • Sync manually added leases without explicit Subnet IDs (d892bfa)

  • The MAC address sync does not write the MAC address to the log (efe1584)

  • The MAC address sync logs only the exception type (c640a61)

  • The old stale cleanup decides each row under the identity lock (2ed6c39)

  • The old sync paths leave an object unchanged when the marker does not fit (7a34f07)

Chores

  • Drop the upstream author from the pyproject authors (becd5d1)

  • Put SPDX copyright headers in each file, with the holders from git blame (284ecb2)

  • deps: Bump the github-actions group with 2 updates (6ed2548)

  • deps: Bump virtualenv (059edae)

  • deps-dev: Bump ruff from 0.16.8 to 0.16.9 (c048769)

  • opengrep: The IPAM sync job catches OSError, not RequestException (bd38c9f)

Code Style

  • Drop em-dashes from the truncation log and the job summary list (3368d49)

Continuous Integration

  • Codecov waits for both coverage uploads before it reports (da527e2)

Documentation

  • A branch delete of an object that a Kea server owns is refused (2723979)

  • ADR 0006, README and AGENTS.md describe the Reservation phase (b2d0e72)

  • ADR 0006, README and CONTEXT describe the marker and owner rules as built (025964b)

  • Generate IPAM ownership upgrade notes (0dfe335)

  • IPAM Ownership links stay in main, and a branch delete that reaches one is refused (2d42645)

  • Lease IP addresses use the Sync VRF, and the summary counts owner disagreements (6996b6b)

  • Refresh generated upgrade notes after develop rebase (41b50d7)

  • Regenerate complete IPAM upgrade guidance (e6ee457)

  • Scope the two-phase last-link rule to IP addresses (f93902f)

Features

  • Add the IPAM ownership link model and the confirmation sequence (2adedde)

  • Reconcile Prefixes and IP Ranges with optional deprecation (c2428c4)

  • Refuse a branch delete that reaches an IPAM ownership link through NetBox's AbortRequest (976c15d)

  • The job's lease phase runs through reconcile() and owns its rows through links (fceb54e)

  • The job's Reservation phase runs through reconcile() (1464be7)

  • The old stale cleanup never touches an IP address with an ownership link (51559a9)

  • The sync marker is a block that keeps the operator note after it (9bdd4dd)

Performance Improvements

  • Skip snapshots for unchanged sync objects (027b8c9)

Refactoring

  • A failed lease snapshot goes through SyncReport.fail_snapshot (b095fe0)

  • A stale link records the cutoff number of its mark (a50241b)

  • Adopt IPAM rows and remove legacy sync paths (aece546)

  • Claim DHCP import IPAM ownership (31ea5dc)

  • Drop Marker.note, which only tests read (251b033)

  • Remove obsolete claim guards and verify upgrade states (8b1d9b9)

  • Run bulk Reservation Sync through reconciliation (afddbfa)

  • The old sync paths drop the two-pass status mode (c1b885f)

Testing

  • An incomplete Reservation snapshot keeps a Reservation link that is not the last (d65f461)

  • Concurrent lease phases, row locks and operator edits on separate connections (4d6ba2f)

  • Guard 2 pins the relations that a delete in a branch reaches (66245fb)

  • IPAM ownership links stay in main through branch sync, discard, merge and revert (534ba21)

  • ui: The browser cleanup finds its NetBox IP by the sync marker (f8c5d09)

Additional Release Information

  • stale_ip_cleanup = "remove" now removes expired leases, deleted Reservations and hostless leases after their last ownership link becomes stale. On upgrade, it removes only lease rows that expire after adoption. Rows already stale get no owner and stay unowned and counted.

  • When every configured Server uses the same non-global sync_vrf, an unowned global marker address moves into it with its primary key and changelog intact. An existing owner or destination collision prevents the move. Mixed VRFs keep the global row. The read-only Server.ipam_first_complete_at field records initial completion across enabled job and DHCP import observations.

Unreleased

Bug Fixes

  • A legacy marker kind ends at a word boundary (8d04bdd)

  • A plain OSError from a sync snapshot fails only that phase (726a0a3)

  • Align ownership routing and sync VRF guidance (a5feaeb)

  • An unknown stale_ip_cleanup mode fails the old cleanup like the reconciliation (198cbf7)

  • Claim IPAM ownership for per-row sync and lease add (98784ed)

  • Cleanup gives an object the hostname of its remaining links (59f9670)

  • KeaClient takes timeout and max_unpaged_leases with no default (30c276c)

  • NetBox refuses to start with an unknown stale_ip_cleanup value (ad3789d)

  • NetBox validates every netbox_kea setting at startup (d2fcc4a)

  • NetBox validates sync_enabled at startup too (00ea72d)

  • One phase compares its own reports with the owner hostname rule (f43ec13)

  • Preserve shared prefix markers and claimed MAC results (3f7a7e1)

  • Reject malformed lease subnet IDs before reconciliation (6816352)

  • Release deprecated IP ownership after operator edits (22a9b38)

  • Remove obsolete lease mask resolver import (5a9f1b1)

  • Resolve lease ownership facts from the Kea catalogue (163ee15)

  • Retain every commit's release guidance in changelog (c12036d)

  • Sync manually added leases without explicit Subnet IDs (a0c5696)

  • The MAC address sync does not write the MAC address to the log (b1fba1d)

  • The MAC address sync logs only the exception type (c08f626)

  • The old stale cleanup decides each row under the identity lock (0902df4)

  • The old sync paths leave an object unchanged when the marker does not fit (f5c26bd)

Chores

  • Drop the upstream author from the pyproject authors (becd5d1)

  • Put SPDX copyright headers in each file, with the holders from git blame (284ecb2)

  • deps: Bump the github-actions group with 2 updates (6ed2548)

  • deps: Bump virtualenv (059edae)

  • deps-dev: Bump ruff from 0.16.8 to 0.16.9 (c048769)

  • opengrep: The IPAM sync job catches OSError, not RequestException (9f8890c)

Code Style

  • Drop em-dashes from the truncation log and the job summary list (443d7af)

Continuous Integration

  • Codecov waits for both coverage uploads before it reports (da527e2)

Documentation

  • A branch delete of an object that a Kea server owns is refused (db04f5d)

  • ADR 0006, README and AGENTS.md describe the Reservation phase (04ba7d0)

  • ADR 0006, README and CONTEXT describe the marker and owner rules as built (6f70b16)

  • Generate IPAM ownership upgrade notes (6fbd846)

  • IPAM Ownership links stay in main, and a branch delete that reaches one is refused (95bce1c)

  • Lease IP addresses use the Sync VRF, and the summary counts owner disagreements (7c22d2c)

  • Refresh generated upgrade notes after develop rebase (cd4cc88)

Features

  • Add the IPAM ownership link model and the confirmation sequence (5785ee3)

  • Reconcile Prefixes and IP Ranges with optional deprecation (6212a9e)

  • Refuse a branch delete that reaches an IPAM ownership link through NetBox's AbortRequest (3e481b2)

  • The job's lease phase runs through reconcile() and owns its rows through links (18a6629)

  • The job's Reservation phase runs through reconcile() (5730d23)

  • The old stale cleanup never touches an IP address with an ownership link (06075aa)

  • The sync marker is a block that keeps the operator note after it (aafdc16)

Refactoring

  • A failed lease snapshot goes through SyncReport.fail_snapshot (1f5fced)

  • A stale link records the cutoff number of its mark (1f84f4d)

  • Adopt IPAM rows and remove legacy sync paths (b3f82c7)

  • Claim DHCP import IPAM ownership (ce8826f)

  • Drop Marker.note, which only tests read (eec09fb)

  • Remove obsolete claim guards and verify upgrade states (1c8c571)

  • Run bulk Reservation Sync through reconciliation (4a23238)

  • The old sync paths drop the two-pass status mode (2cf29c2)

Testing

  • An incomplete Reservation snapshot keeps a Reservation link that is not the last (a24889a)

  • Concurrent lease phases, row locks and operator edits on separate connections (67fd33f)

  • Guard 2 pins the relations that a delete in a branch reaches (0938dfb)

  • IPAM ownership links stay in main through branch sync, discard, merge and revert (0840a59)

  • ui: The browser cleanup finds its NetBox IP by the sync marker (8229a76)

Additional Release Information

  • stale_ip_cleanup = "remove" now removes expired leases, deleted Reservations and hostless leases after their last ownership link becomes stale. On upgrade, it removes only lease rows that expire after adoption. Rows already stale get no owner and stay unowned and counted.

  • When every configured Server uses the same non-global sync_vrf, an unowned global marker address moves into it with its primary key and changelog intact. An existing owner or destination collision prevents the move. Mixed VRFs keep the global row. The read-only Server.ipam_first_complete_at field records initial completion across enabled job and DHCP import observations.

v1.12.0 (2026-10-01)

Bug Fixes

  • A Reservation mutation requires exactly one reply from Kea (b76b07f)

  • Every KeaClient must carry a write guard (4deb722)

  • KeaIpamSyncJob.enqueue_once accepts a positional interval (6491095)

  • Keep every netbox_kea model in main with a constant resolver (09eb53b)

  • Let an error in the SyncConfig save fail as a server error (66a0709)

  • Make the branch banner a navbar button, because NetBox renders the navbar twice (3a856c3)

  • Migration 0018 refuses an invalid sync_interval_minutes by name (818efc3)

  • Read the sync interval from SyncConfig when the job is scheduled (dd4e44c)

  • Refuse a Kea configuration write before the cache invalidation (9780e03)

Chores

  • deps: Bump the uv group across 1 directory with 3 updates (37cd8d1)

Continuous Integration

  • Pin the NetBox release and netbox-branching once, and reuse the integration steps (f383043)

  • Read the coverage settings from pyproject in the branching-test job (4972f71)

  • Run the branching browser tests on the netbox-branching harness variant (40fbd87)

  • Run the netbox-branching tests with NetBox 4.7.0 and netbox-branching 1.2.1 (e94c957)

  • Upload the branching-test coverage to Codecov (9f3bfcd)

Documentation

  • Delete, do not merge, a pre-upgrade branch that changed a Kea server password (3a5c1f0)

  • Describe the increment 4 branching sinks (dbb6efd)

  • Drop an em-dash from the KeaClient paragraph in AGENTS.md (35af538)

  • Reflow the increment 3 note, add the GraphQL case and the issue numbers (20cd0f7)

  • Say in AGENTS.md that every KeaClient takes a write guard (a917e4b)

  • Say in the README that a branch refuses plugin writes outside a web request too (5206294)

  • Say that the plugin refuses changes in a branch, and record increment 3 (c8b72b9)

  • Say the migration reads PLUGINS_CONFIG once to create the SyncConfig row (fbb1659)

  • Say the Sync Jobs page sets the sync interval, not NetBox admin (eb0df49)

  • Say where the branching browser tests run, and what the banner is (b92a535)

  • Say which unusable branch selections get netbox-branching's HTTP 400 (04d1542)

  • State the sync VRF protection and the partial netbox-branching support (4772200)

Features

  • Create the SyncConfig row in a migration, so a GET of a sync page writes nothing (1f08395)

  • Fake every netbox_kea migration on a branch, and check it (c3fb487)

  • KeaClient.command() takes a KeaCommand member and a target family (5ecbb7a)

  • KeaIpamSyncJob fails in a branch before any read (ed0a3c3)

  • Keep netbox_kea rows in main when netbox-branching is installed (ed93a49)

  • Protect a VRF that a Server syncs into (cad0731)

  • Refuse a save or a delete of a netbox_kea row in a branch (4e2f4d3)

  • Refuse plugin changes in a branch, and name the sources of plugin responses (606f6c9)

  • Show a branch banner on plugin pages, and no reservation links on the IP panel (1d3355d)

  • The Kea transport refuses a write command in a branch (4b5907a)

Refactoring

  • Drop the Reservation reply checks that command() already makes (d881e5f)

  • KeaCommand.is_write names the write kind once (4438948)

  • Keep the branch-refusal receivers in branching.py (450d158)

  • Take SAFE_METHODS from REST framework, and name each refusal code once (479b080)

Testing

  • A failed cache invalidation is logged, and the change is still sent and persisted (096fa6b)

  • A merge that deletes a VRF a Server now syncs into fails and changes nothing (bfe373a)

  • A REST view outside the plugin gets netbox-branching's 400 for an unready branch header (cf1b639)

  • Add a netbox-branching harness variant and browser tests for Sync all (b608b80)

  • Add archived, failed and empty-cookie rows to the selector table (7a19222)

  • An empty reply to reservation-add raises before the persist step (7764ba3)

  • BranchActive from a view outside the plugin also gets the 409 (c3916bc)

  • Browser tests compare the state from before the page loads (7494e9b)

  • Guard 1 sends every method to every plugin URL in a provisioned branch (bb09994)

  • Guard 1 sends POST, PUT, PATCH and DELETE to every plugin route (b475ec0)

  • Let the test settings and the CI configuration writer load netbox-branching (6f511fe)

  • Name three KeaClient.command() tests after what they assert (28c2f84)

  • Pass timeout= to the CI configuration writer run (5024170)

  • Prove the SyncConfig row on a fresh database comes from migration 0018 (cb57cba)

  • Put the KeaClient.command() tests in their own class (ec0a5c0)

  • Remove an unused Kea command helper that used the old command() signature (af0249a)

  • The boundary scanner reports a KeaCommand attribute that is not a member (93ac74a)

  • The boundary scanner treats a mapping-pattern capture as a rebinding (fdd80de)

  • The reservation boundary scanner resolves a name only through its kea import (7c600f3)

  • Type the cache-invalidation refusal test, so mypy checks its body (6c3b7bc)

  • Type the guard 4 helpers with Sequence, as SeparateDatabaseAndState holds them (082adc7)

v1.11.0 (2026-10-01)

Bug Fixes

  • Build the Subnet update before the first step, so an edit that NetBox cannot build sends nothing (aab511e)

  • Compare a Subnet lifetime or timer only when the edit writes it (9aa05f9)

  • Keep Shared Network facts out of the Catalogue, and fail closed on an unknown membership (3807b49)

  • Keep the option text that Kea holds when a save leaves the value (304e095)

  • Name a live value that the edit form cannot show (c0e6c0e)

  • Name config-set in the help of the shared network and server options edit pages (9d76e31)

  • Redirect the Pool add GET when NetBox cannot confirm the Subnet (bc30b73)

  • Refuse a Shared Network or Subnet edit whose shown values changed in Kea (7cdd103)

  • Refuse a Subnet edit when a live Pool entry is malformed, instead of dropping it (94454fa)

  • Refuse a Subnet form whose page could not load the Shared Networks (ec21d5f)

  • Scan only comments and docstrings for source line numbers, and say an unknown membership sends no undo (4cc3c5f)

  • Select the managed DHCP Option entry with one rule for display and save (fb00a3b)

  • Show why Kea could not persist a Reservation change (aa24096)

  • config_write: Catch only a malformed configuration, and require a Verified Subnet for Subnet options (9557842)

  • config_write: Check the Pool before the send, and keep ID reuse from reading as a rejection (21a0d39)

  • config_write: Keep the outcome when the lock transaction fails to commit after the change (3452dc2)

  • config_write: Refuse a Subnet edit whose Shared Network changed after the page (ac350b5)

  • config_write: Send Subnet delete and Pool writes only to the Subnet the page showed (fe1b182)

  • dhcp_options: Refuse a save when a shown option value changed (1040349)

  • kea: Keep the Pool-level fields of each Pool that a Subnet edit keeps (8eb8005)

  • kea: Send Pool changes only as subnet delta commands (f2e0ece)

  • opengrep: Exempt only a lambda passed to _run_config_change (405ff45)

  • opengrep: Refuse a _run_config_change defined outside views/_base.py (6e75f4c)

  • scripts: End a stalled download in the Kea recording script (9ef124b)

Chores

  • coverage: Exclude raise NotImplementedError (a13bc03)

  • opengrep: Require timeout= on every subprocess call (2576714)

Continuous Integration

  • Make the unit-test coverage run read pyproject's coverage config (c85e9d1)

Documentation

  • Escape the pipe in Family | None, so the R4-N1 row keeps four columns (5e4bfa9)

  • Netbox-branching compatibility design (ratified r6) and ADR 0007 (9d66dcf)

  • Remove the review history from the netbox-branching design (88f0188)

  • Say which read each check under the lock sends (d1ea9bd)

  • Scope two netbox-branching acceptance conditions to the contract table (c882ce2)

  • Tell operators that a database idle timeout can end the change lock (4c5670b)

  • adr: ADR 0007 names the writes that its branch refusal does not cover (d9f9347)

  • adr: Say that the ADR 0007 refusals arrive in the tracked increments (77a2431)

  • agents: Name #207 as the removal ticket, and say that old write paths skip the lock (2fdc7c4)

Features

  • Log a Configuration Change that holds the Kea server lock longer than the lock wait (c428c04)

  • config_write: Add the Configuration Change outcome and use it for Shared Network add and delete (6d56f99)

  • opengrep: Refuse a broad except around a config_write call in a view (b84c9d5)

Performance Improvements

  • Check a Subnet after a step with one Subnet list read (3fe210b)

  • Send no config-get from the Subnet add and edit POST (a91524a)

  • Take the target Shared Network from the Subnet scope read (fe60730)

Refactoring

  • Delete the last old write exceptions, and refuse a view that catches the rejection (61ad2be)

  • Move the form option projection to dhcp_options (981fe1a)

  • One typed Pool parser, with Pool form errors for out-of-Subnet and overlapping Pools (#216, c1ecf1a)

  • Rename the Subnet membership fields to original_network (e6cb2bd)

  • config_write: Add a Subnet and assign it to a Shared Network as one change (#223, 390c151)

  • config_write: Edit a Subnet and move it between Shared Networks as one change (2dc2645)

  • config_write: Run the read-modify-write changes through config_write (04ed6bd)

  • forms: Derive the hidden shown copies from one declaration (5a2df92)

  • pools: Move the Pool type and its parser below kea.py (8c383a4)

  • reservations: Use the shared config_write persist step (#219, 2d5c4d0)

Testing

  • Assert the commands of the refused GET in the null option-data edit test (3b440c4)

  • Cover a failed Pool sync in the IPAM job (dee9c38)

  • Fail loudly when a stub Subnet names a Shared Network that the stub does not hold (d0a9ab9)

  • Fail on a source line number in a comment or docstring (bd79cef)

  • Name the behaviour instead of source line numbers in test docstrings (90b61e6)

  • Name the code that the Subnet view tests exercise today (7cd4de7)

  • Name the inherited option tests after _inherited_subnet_options (e44f86f)

  • Refuse a dotted --cov source, which splits the psycopg error classes (f257e01)

  • config_write: A Pool failure whose read shows the change and another writer's Pool is unknown (fe4cdbb)

  • config_write: Cover a non-lock database error and a missing TLS file on the change (2c6debf)

  • config_write: Cover the Subnet options target checks and a config-get without a configuration (b0be1d2)

  • config_write: Tighten the Pool-keep test to an NTP-only save (741c9ea)

  • kea: Take Kea command names from a recorded list-commands reply (d2990cf)

  • kea_stub: Answer the Subnet edit commands in SubnetDaemon (c9e993c)

  • kea_stub: Check the commands that a list-commands Response object advertises (be294b1)

  • subnets: Remove subnet_cidr from the Kea Pool objects in two fixtures (8d4cf9d)

  • views: A Subnet that Kea holds in another text form saves from its page (eaa8fe4)

v1.10.2 (2026-09-28)

Bug Fixes

  • Run each DHCP-plugin import write in a savepoint, and pass sync a parsed Subnet network (#199) (#215, c449171)

Chores

  • deps: Bump the github-actions group with 4 updates (#193, c5abb6b)

  • deps-dev: Bump djangorestframework-stubs from 3.17.1 to 3.18.0 (#163, 3f91cd8)

  • deps-dev: Bump python-semantic-release from 10.6.2 to 10.7.0 (#192, 242ed87)

  • deps-dev: Bump ruff from 0.16.7 to 0.16.8 (#191, e059a51)

Documentation

  • Record the Config Write outcome and IPAM ownership decisions (#195, cb2d712)

Testing

  • ui: Assert the harness data exists instead of skipping (#160) (#194, 046e625)

v1.10.1 (2026-09-21)

Bug Fixes

  • ui: Hide the Help button this package ships no page for (#181, c197115)

v1.10.0 (2026-09-19)

Bug Fixes

  • Catalog (#142, 4872b00)

  • Restore pytest-django database semantics and repair a squashed-away migration dependency (#153) (#159, b76318b)

  • Send Kea's subnet lifetime parameter names on subnet update (#177, 266679e)

Chores

  • deps: Bump codecov/codecov-action from 7.0.0 to 7.1.0 in the github-actions group (#167, 96496ce)

  • deps: Bump sqlparse in the uv group across 1 directory (#138, 09640c9)

  • deps: Bump the github-actions group across 1 directory with 3 updates (#158, e1b2a95)

  • deps: Bump the github-actions group with 2 updates (#149, 5df698e)

  • deps: Bump the github-actions group with 3 updates (#145, d7e870e)

  • deps: Bump the uv group across 1 directory with 2 updates (#162, 45480dd)

  • deps-dev: Bump mypy from 2.3.0 to 2.3.1 (#143, f90aacd)

  • deps-dev: Bump pre-commit from 4.6.1 to 4.6.2 (#134, 68a135d)

  • deps-dev: Bump pytest-django from 4.12.0 to 4.14.0 (#133, 872a5d6)

  • deps-dev: Bump pytest-playwright from 0.8.0 to 0.9.0 (#164, 7f3bfba)

  • deps-dev: Bump pytest-playwright from 0.8.0 to 0.9.0 (#136, 93be512)

  • deps-dev: Bump python-semantic-release from 10.6.1 to 10.6.2 (#151, 6f040f2)

  • deps-dev: Bump ruff from 0.16.1 to 0.16.2 (#135, 3291763)

  • deps-dev: Bump ruff from 0.16.2 to 0.16.3 (#144, 67dc1c1)

  • deps-dev: Bump ruff from 0.16.3 to 0.16.4 (#148, a5f5a95)

  • deps-dev: Bump ruff from 0.16.4 to 0.16.6 (#156, 4bb5fab)

  • deps-dev: Bump ruff from 0.16.4 to 0.16.7 (#166, 32cefd7)

  • deps-dev: Bump types-pyyaml from 6.0.12.20250915 to 6.0.12.20260906 (#165, 108f76c)

  • deps-dev: Bump types-requests (#157, a2ee20b)

Documentation

  • Record the Server Configuration split and track the ADRs (#176, 8a6b0da)

Features

v1.9.0 (2026-08-13)

Features

  • Read subnet suggestions from subnet_cmds on both datalists (#119, 6727f4f)

v1.8.0 (2026-08-11)

Chores

  • deps: Bump django in the uv group across 1 directory (#118, ed0c684)

  • deps-dev: Bump ruff from 0.16.0 to 0.16.1 (#115, 315e001)

Features

  • Replace subnet_id with subnet_cidr on reservation add/edit forms (0e03fb8)

v1.7.2 (2026-08-07)

Bug Fixes

  • Handle invalid CA paths in status badge (#117, baae8c3)

Chores

  • deps: Bump gitpython in the uv group across 1 directory (#112, 44a4d59)

  • deps: Bump the github-actions group with 2 updates (#116, 34eaad2)

  • deps-dev: Bump types-requests (#114, 939ac51)

v1.7.1 (2026-07-28)

Bug Fixes

  • Render and manage reservations that reserve no address (#111, 49084ca)

Chores

  • deps: Bump the github-actions group with 2 updates (#103, e6d43b1)

  • deps-dev: Bump mypy from 1.19.1 to 2.3.0 (#107, adb49ef)

  • deps-dev: Bump pre-commit from 4.5.1 to 4.6.1 (#105, 80255e0)

  • deps-dev: Bump pynetbox from 7.6.1 to 7.8.0 (#108, 9c21e4e)

  • deps-dev: Bump python-semantic-release from 10.5.3 to 10.6.1 (#104, 812b31f)

  • deps-dev: Bump ruff from 0.15.2 to 0.16.0 (#106, c8d8823)

Continuous Integration

Testing

  • jobs: Drive the sync-job tests through a real KeaClient (#101, 1361808)

  • server: Add NetBox ViewTestCases/APIViewTestCases coverage for Server (#102, 4d279d0)

  • ui: Make configure_table wait for column moves to land (#109, af1b0ec)

v1.7.0 (2026-07-23)

Chores

  • deps: Bump gitpython in the uv group across 1 directory (#98, 13c2164)

Features

  • Omit the Kea 'service' arg on direct-daemon connections (#99, b4c15ec)

Testing

  • De-mock the view tests (PR A) — real KeaClient + HTTP-boundary stub (#97, 368adad)

v1.6.0 (2026-07-22)

Chores

  • Cover .github/CODEOWNERS in REUSE.toml (#85, 2413516)

  • deps: Bump requests from 2.33.0 to 2.34.2 (#86, 1958b0d)

  • deps: Bump the github-actions group with 7 updates (#89, cdfb522)

  • deps: Bump the uv group across 1 directory with 2 updates (#93, edd89d4)

  • deps: Bump the uv group across 1 directory with 3 updates (#92, bfb2e7c)

  • deps-dev: Bump pytest from 9.0.3 to 9.1.1 (#91, cbf2c2e)

  • deps-dev: Bump pytest-cov from 7.0.0 to 7.1.0 (#90, ec3e23c)

  • deps-dev: Bump pytest-playwright from 0.7.2 to 0.8.0 (#88, f9d3bd4)

  • deps-dev: Update django-stubs[compatible-mypy] requirement (#87, 4b11de3)

Continuous Integration

  • Kea 3.0+ support — reframe Control Agent, test against Kea 3.0.3 (#95, 61b05bc)

  • Streamline NetBox matrix (floor/ceiling/dev) + pin driver Python (#94, 575b32d)

Features

  • Add support for DDNS Qualifying Suffix on subnets (#83, 36cf684)

Testing

  • Stabilize two flaky Playwright UI tests (#96, bca241c)

v1.5.2 (2026-07-21)

Bug Fixes

  • Allow auto-id to work when there's empty subnets (#84, 6884a53)

Chores

  • Add CODEOWNERS to auto-request @marcinpsk on PRs (1f14e9f)

Continuous Integration

  • Ruff bandit (S) rules + custom opengrep ruleset (on top of CodeRabbit) (#82, 1f9d986)

v1.5.1 (2026-06-22)

Bug Fixes

  • combined: Validate Kea response shape before indexing resp[0] (#81, ac12a2e)

v1.5.0 (2026-06-20)

Features

v1.4.5 (2026-06-18)

Bug Fixes

v1.4.4 (2026-05-30)

Bug Fixes

  • Move ghost-job self-heal out of ready(); migrate deprecated querystring tag (#70, 9f651f6)

Chores

  • Update envrc example and test infrastructure configuration (#69, 1a73b87)

Documentation

  • Update copilot instructions, CLAUDE.md, README; add .envrc.example; freeze uv.lock (#68, f83d9d1)

v1.4.3 (2026-05-14)

Bug Fixes

  • Self-heal ghost scheduled-job DB records on worker startup (#67, 0457b3b)

v1.4.2 (2026-05-13)

Bug Fixes

  • Use condition= instead of deprecated check= in CheckConstraint migration (#66, 56f74d5)

v1.4.1 (2026-05-08)

Bug Fixes

v1.4.0 (2026-05-01)

Features

  • Sync Kea subnets to NetBox Prefixes and pools to IPRanges (#62, 473f15f)

v1.3.3 (2026-04-10)

Bug Fixes

  • Remove DB query from AppConfig.ready() (#60, 2e3ed06)

v1.3.2 (2026-04-09)

Bug Fixes

  • Sync version in init.py on semantic-release version bumps (#58, 8cf7668)

v1.3.1 (2026-04-09)

Bug Fixes

v1.3.0 (2026-04-07)

Features

v1.2.0 (2026-04-05)

Features

v1.1.1 (2026-03-24)

Bug Fixes

  • Hide server password in change log (0e0ce2e)

v1.1.0 (2026-03-23)

Features

v1.0.4 (2026-02-10)

v1.0.3 (2025-09-14)

v1.0.2 (2025-07-03)

v1.0.1 (2024-09-10)

v1.0.0 (2024-05-23)

v0.2.0 (2023-08-22)

v0.1.1 (2023-06-21)

v0.1.0 (2023-05-17)

  • Initial Release