v3.0.0 — Field-level policies
DynamicWhere.ex 3.0 adds field-level policies: a layer that decides, per caller, what may be filtered, sorted, selected, grouped, aggregated and seen. Attributes carry the rules you ship; an optional store carries the rules you change at runtime.
It is entirely opt-in. A project with no policy attributes and no DwPolicy.Configure call behaves exactly as 2.1.5.
dotnet add package DynamicWhere.ex --version 3.0.0Packages
| Package | What it is |
|---|---|
| DynamicWhere.ex | The library, now with the policy layer, an in-memory rule store and an in-memory token vault |
| DynamicWhere.ex.Policies.EntityFrameworkCore | New. Rules and tokens in your own database, through any EF Core provider |
| DynamicWhere.ex.Policies.Redis | New. Rules and tokens in Redis, with changes reaching every instance through pub/sub |
| DynamicWhere.ex.Policies.AspNetCore | New. Admin API, schema discovery, explain, simulate, health and audit |
What's new
- Access control.
[DwDeny]and six named attributes across Where, Select, Order, Group, Aggregate and Segment;[DwOperators];[DwEntity(RequirePolicy = true)]. - Injection.
[DwAlias],[DwForceWhere],[DwRequireWhere]. - Transformation.
[DwMask]with nine strategies — among themHash, keyed HMAC-SHA256, andTokenize, random tokens kept in a vault — plus[DwMutate],[DwDefault],[DwGeneralize],[DwTruncate]and[DwFormat]. Filtering and sorting still run against the real value in SQL; the transformation is applied to the result. - Precedence. Six levels, with attributes sealed by default.
- Dynamic rules. An optional store with broad and narrow zones and three failure modes. The in-memory, Redis and EF Core stores all pass one conformance suite.
- Admin surface. Mounts only with a named authorization policy — there is deliberately no default.
- Configuration. The whole posture binds from
IConfiguration, and an unrecognised key refuses to start. - Inference defences. The seven inference channels in the design's threat model are closed, including a k-anonymity floor on grouped summaries.
Before you turn it on
- The group floor ships on, at 5. A guarded grouped summary suppresses groups of fewer than five rows. It cannot change an existing query, because only guarded queries are affected and those are new.
MinGroupSize = 1turns it off. - A mask does not stop sorting or filtering. Both run on the real value. Pair a mask with
[DwNoOrder], and with[DwOperators]where comparisons could narrow the value down. - Neither
HashnorTokenizehides equality. Both keep a column groupable and joinable, so equal values stay equal. A field that cannot accept that needsFixed,Nullor a denial. - Transforming values costs something. Gating is free, but rebuilding every value of a large result costs about 1.6× in time and 7× in allocations.
Compatibility
No breaking changes to the 2.x API. FilterResult<T> and SummaryResult each gain one nullable Policy property, null when a query was not guarded. Targets net6.0 and runs on .NET 6 through 10, with EF Core 6.0.22 or later.
Verified
The release workflow ran 1,660 tests on EF Core 8 and 1,184 on the EF Core 6.0.22 floor before it packed. The store and token-vault conformance suites run against real Redis and PostgreSQL.
Documentation: Policies · Use cases · Security · For AI agents
Pull request: #2