Commit Graph

15866 Commits

Author SHA1 Message Date
Martin Hauser f46090076d refactor(graphql): Update filter lookups for strawberry-django 0.86
Update strawberry-graphql-django to 0.86.1 and remove redundant type
parameters from StrFilterLookup, DateFilterLookup, TimeFilterLookup, and
DatetimeFilterLookup annotations across model-backed GraphQL filters.

Add NetBox-local JSON date, time, and datetime lookup input types to
preserve the previous string-backed JSON filter schema without relying
on deprecated upstream generic lookup annotations. These local types
keep the legacy GraphQL type names and date/time sub-lookup fields
intact.

Fixes #22353
2026-06-16 08:50:03 -04:00
Jeremy Stretch 16c70c3657
Fixes #22448: Ensure all objects are escaped under handle_protectederror() (#22449) 2026-06-16 13:43:52 +02:00
Jason Novinger 89504b2502
Closes #21992: Enable background job support for REST API bulk requests (#22452)
Bulk write operations (create/update/delete a JSON list at a model's list
endpoint) can opt into background processing with the ?background=true query
parameter. The request is validated synchronously and, if accepted, an
AsyncAPIJob is enqueued and a 202 Accepted is returned with the job id and
poll URL; the write is performed later by a worker that re-invokes the same
viewset action, so behavior matches the synchronous path (including
all-or-nothing transaction semantics).

- AsyncAPIJob reconstructs the request in the worker, re-applies object
  permissions, runs within the request processors (change logging/events),
  and captures the action's response into job.data as {status_code, data}.
- Handled rejections are translated to match the synchronous API: APIException
  via handle_exception(), and AbortRequest/ProtectedError/RestrictedError via a
  new NetBoxModelViewSet.exception_to_response() helper. These terminate the
  job as "failed" (reserving "errored" for unexpected crashes).
- Background processing is refused with 503 when no worker is servicing the
  queue, and rejected with 400 when combined with an If-Match precondition
  (which cannot be honored once execution is deferred).
- Single-object writes, GET requests, and non-list payloads ignore the
  parameter and run synchronously.

exception_to_response() intentionally duplicates the translation logic in
dispatch() rather than dispatch() being refactored to call it; consolidating
the two is left as a follow-up to keep this change off the synchronous hot path.

* Address code review feedback (#21992)

- Carry the request's scheme and host into the background worker so absolute
  URLs in the captured job result point at the real server instead of a
  hardcoded http://localhost/.
- Emit the same protected-delete warning log in exception_to_response() that
  dispatch() produces, restoring application-log parity for background failures.
- Drop the inert `_authenticator = None` assignment: setting request.user
  already prevents lazy re-authentication via the public API, and nothing on
  the worker's action path reads the authenticator.
- Remove the redundant success-path job.save() (JobRunner.handle() ->
  terminate() persists job.data) and hoist the AsyncAPIJob import in mixins.py
  to module level (no real import cycle through it).
- Add a test asserting result URLs reflect the request host.

* Fix IPv6 host parsing in background API request reconstruction

Parse the carried host with urlsplit (and pass it verbatim as HTTP_HOST)
instead of host.partition(':'), which split bracketed IPv6 hosts like
[::1]:8443 on their inner colons. Extract request construction into
AsyncAPIJob._build_request and add a test asserting the IPv6 host round-trips.

* Address review feedback (#21992)

- Make the bulk mixins safe to use without BackgroundOperationMixin: guard the
  _background_requested / _maybe_background_bulk_create calls with a getattr
  fallback so BulkUpdateModelMixin/BulkDestroyModelMixin/SequentialBulkCreatesMixin
  retain their standalone behavior in custom viewset composition.
- Add a test covering the background ProtectedError/RestrictedError path: a bulk
  delete of a protected object records the same 409 the synchronous API returns
  (job failed, status_code 409, object preserved), via exception_to_response().
2026-06-16 12:48:17 +02:00
Jeremy Stretch 0994ce9f0c
Closes #22457: Use `hmac.compare_digest()` to authenticate API tokens (#22458) 2026-06-16 04:51:36 -05:00
Martin Hauser 025074c390
Closes #22280: Set 91% test coverage threshold and exclude non-testable paths (#22450) 2026-06-16 04:38:21 -05:00
github-actions 1264797fa6 Update source translation strings 2026-06-16 06:47:17 +00:00
bctiemann cfc5414922
Merge pull request #22459 from netbox-community/21355-denormalize
#21355 - Handle updates to denormalized data via PostgreSQL triggers
2026-06-15 19:05:01 -04:00
bctiemann 2d496ca069
Merge pull request #22455 from netbox-community/22451-pass-strawberry-graphql-extension-factories-instead-of
Closes #22451: Use factories for GraphQL schema extension initialization
2026-06-15 19:02:11 -04:00
Jeremy Stretch 9bfdea4787
Fixes #22454: Fix serialization of decimal custom field values (#22460) 2026-06-15 22:24:10 +02:00
Jason Novinger b7de62610f Fixes #22395: Remove unused save() override on ManagedFileForm
The method wrote uploaded files to disk via a raw open(), but no code
path reached it. Its only subclass, ScriptFileForm, overrode save() to
write through django-storages and explicitly skipped the base via
super(ManagedFileForm, self).save(). With the override gone, that call
simplifies back to a plain super().save(). A leftover from #18680, which
moved both upload paths onto django-storages but left the form-level
write in place.
2026-06-15 14:07:46 -04:00
Arthur 614eb7c6c1 fix review comments 2026-06-15 10:54:23 -07:00
Arthur 0bd5909cf0 cleanup 2026-06-15 10:39:06 -07:00
Arthur 041e749996 cleanup 2026-06-15 10:38:11 -07:00
Arthur 57094ffdfd #21355 - Handle updates to denormalized data via PostgreSQL triggers 2026-06-15 09:18:17 -07:00
Martin Hauser eaed2a7f8e
refactor(graphql): Use factories for schema extension initialization
Change `get_schema_extensions()` to return extension factories instead
of instances. This defers extension initialization and prevents stale
references to settings captured at import time.

Lambdas capture settings values when extensions are constructed, and
tests now instantiate extensions from factories to verify configuration.

Fixes #22451
2026-06-15 15:34:22 +02:00
Martin Hauser d7de863681
Closes #17598: Add bulk creation for VLANs (#22377) 2026-06-15 08:22:58 -05:00
Jeremy Stretch 8afbfc42d5
Fixes #22346: Return a clean error message & redirect on SSO auth failure (#22420) 2026-06-15 07:51:06 -05:00
github-actions c889e58bee Update source translation strings 2026-06-15 06:46:14 +00:00
Fabi bf1a27b89c
Fixes #22397: Fix AttributeError exception for unauthentictaed users during bulk export 2026-06-14 10:34:51 -04:00
github-actions 850aae2d35 Update source translation strings 2026-06-14 06:31:05 +00:00
Jeremy Stretch 8ff56032b9
Fixes #22444: Fix KeyError exception on device view with non-English locale (#22445) 2026-06-14 02:10:29 +02:00
Tobias Genannt b4fdd6f209 Closes #22333: Use lowercase username for testing
The test failures arises from unstable sorting of the usernames
depending on the collation used in the PostgreSQL database used for
testing. When a case-insensitive collation is used 'testuser' is sorted
before 'User*' and because this user has permissions assigned and
additional query is issued resulting in 12 queries. When a
case-sensitive collation is used the sorting is inverted. Because the
'User*' don't have permissions only 11 queries are sent to the database.

Using only testusers with lowercase names enforces stable sorting
across collations.
2026-06-13 19:42:21 -04:00
Arthur Hanson 8d941047b8
Closes #21418: Replace MPTT wtih PostgreSQL Ltree (#22296) 2026-06-13 19:39:05 -04:00
Martin Hauser 8f974e3cc8 perf(ipam): Optimize Prefix availability calculations
Replace IPSet-heavy Prefix availability and utilization logic with
indexed host lookups, distinct host counts, and interval-based
availability calculation.

This adds mask-insensitive host-bound filtering for IP addresses and
ranges, moves availability/counting behavior onto QuerySet and model
methods, and uses merged occupied intervals to find available addresses
without materializing large address sets in Python.

Prefix utilization remains on a cheap utilization-only path for list
views, while Prefix detail views can use a shared usage summary when
both utilization and available IP count are needed. Usable IP bounds now
live on the Prefix model, since the logic depends on Prefix-specific
state such as is_pool.

This also adds host expression indexes for IP Ranges, fixes zero-address
preparation, fixes child IP matching across differing mask lengths,
keeps Prefix hierarchy rebuilding scoped to the existing VRF/global API,
and preserves IPRange.first_available_ip as a cached compatibility
wrapper.

Fixes #21870
2026-06-13 18:02:51 -04:00
bctiemann 1f0d505b91
Closes: #15165 - HTMX partial fieldset re-rendering for HTMXSelect forms (#22345) 2026-06-13 17:57:40 -04:00
Brian Tiemann ac513345b5 Closes #22436: Rename jinja2_filters/get_jinja2_context/register_jinja2_filters to drop the '2' suffix
Follow-up to #22363: align the plugin hook names with the already-renamed
JINJA_FILTERS setting (#22288) and with the rest of the codebase's 'Jinja'
spelling convention.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 09:20:42 -04:00
Arthur Hanson 0b192cf588
Closes #22411:Enforce token write ability when executing custom scripts via the REST API 2026-06-12 09:16:41 -04:00
bctiemann bc7ed0e9bb
Merge pull request #22434 from netbox-community/22303-openapi-fields-omit
Fixes #22303: Annotate fields & omit parameters in OpenAPI schema
2026-06-12 08:38:34 -04:00
github-actions acef3ac112 Update source translation strings 2026-06-12 06:31:01 +00:00
bctiemann d1919627ce
Closes #22429: Enforce ObjectPermission constraints on grant_token (#22424) 2026-06-11 13:30:27 -07:00
github-actions 65454d30db Update source translation strings 2026-06-11 06:32:06 +00:00
Jeremy Stretch d59f5f4381 Fixes #22303: Annotate fields & omit parameters in OpenAPI schema 2026-06-10 13:55:29 -04:00
Brian Tiemann 97a1375a82 Security: replace random.choice with secrets.choice in Token.generate()
Token.generate() used Python's random module (Mersenne Twister PRNG).
Mersenne Twister is not a CSPRNG: observing ~624 outputs from the same
worker process allows full state recovery and prediction of subsequent
outputs. Any token minted in the same worker within that window becomes
predictable, including tokens for privileged accounts.

Fix: replace random.choice with secrets.choice. secrets is backed by
os.urandom() / getrandom() which provides OS-level CSPRNG entropy and
is immune to state-recovery attacks.

The import of the now-unused random module is removed.

Regression tests:
- test_generate_uses_csprng: patches secrets.choice with wraps= to
  confirm it is called exactly TOKEN_DEFAULT_LENGTH times per generate().
- test_generate_length_parameter: verifies length= is respected and
  output is drawn only from TOKEN_CHARSET.

Ref: SR-001 / VM-317 (internal security review, R1-F07 / R3-F1)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 13:16:12 -04:00
Jeremy Stretch c63e3a8b80
Fixes #22421: GraphQLTestCase should support relative imports (#22422) 2026-06-10 09:48:35 -07:00
mburggraf b4116f2532
Fixes #22273: Fix migration failure when a service has thousands of ports defined 2026-06-10 12:27:50 -04:00
github-actions 34f2ca6f84 Update source translation strings 2026-06-10 06:35:05 +00:00
Jeremy Stretch 9f905cf842 Closes #22288: Rename JINJA2_FILTERS to JINJA_FILTERS 2026-06-09 14:49:31 -04:00
mburggraf f732a8e878
Fixes #22376: Remove files from request for script action event rules 2026-06-09 13:55:20 -04:00
bctiemann 8f972b89e3
Merge pull request #22410 from netbox-community/22409-force-random-tokens
Closes #22409: Disallow chosen-plaintext API tokens
2026-06-09 13:15:43 -04:00
github-actions c81bd39f7d Update source translation strings 2026-06-09 06:21:09 +00:00
Jeremy Stretch 814050a3c9 Closes #22409: Disallow chosen-plaintext API tokens 2026-06-08 14:14:30 -04:00
Jeremy Stretch 70391e5a0b
Closes #22392: Deprecate support for Redis 5.x (#22405) 2026-06-08 09:28:31 -07:00
Jeremy Stretch 87c53aaaeb
Fixes #22399: Enforce object permissions for relevant static media (#22400) 2026-06-08 16:05:39 +02:00
bctiemann 6121418f5a
Merge pull request #22391 from netbox-community/22349-minimum-redis-version
Closes #22349: Correct documentation to reflect minimum Redis version of 5.0
2026-06-08 08:40:21 -04:00
bctiemann 5b6d7887f2
Closes #22351: Add jinja2_filters plugin hook and get_jinja2_context() for config template extensibility (#22363) 2026-06-05 13:29:32 -07:00
github-actions 22d0b22fc9 Update source translation strings 2026-06-05 06:29:27 +00:00
bctiemann f4d95e6e9d
Merge pull request #22384 from netbox-community/15569-add-better-tests-for-graphql-filtering-and-lookup
Closes #15569: Auto-generate GraphQL filter tests for API test cases
2026-06-04 19:17:17 -04:00
Martin Hauser 86ea67d640 fix(extras): Prevent direct access to TableConfig create view
Add GET handler to TableConfigEditView that redirects users to home with
a warning if they attempt to access the create form directly without
required object_type and table parameters from a source list view.

Fixes #22237
2026-06-04 15:58:58 -04:00
Alex Houlton b905e99e63
Closes #22375: Fix VLAN filter_interface_id performance: use UNION instead of OR across M2M joins (#22387) 2026-06-04 15:50:39 -04:00
Jeremy Stretch d592afe56c Closes #22349: Correct documentation to reflect minimum Redis version of 5.0 2026-06-04 14:57:03 -04:00