Skip to content

feat(filter)!: remove prevented and unknown clauses by default - #126

Open
pdevito3 wants to merge 1 commit into
mainfrom
fm/qk-breaking-ignored-clause
Open

pdevito3 wants to merge 1 commit into
mainfrom
fm/qk-breaking-ignored-clause

Conversation

@pdevito3

Copy link
Copy Markdown
Owner

For later consideration in a major version. Do not merge now. #122 made ReplaceWithTrue the default to keep v1.x non-breaking. This PR makes Remove the default again.

The IgnoredClauseBehavior setting stays. A consumer can set it to ReplaceWithTrue to keep the v1.14.2 behavior.

Summary

 QueryKitSettings
-  IgnoredClauseBehavior = ReplaceWithTrue
+  IgnoredClauseBehavior = Remove

 FilterParser.RemovesIgnoredClauses
-  config is QueryKitConfiguration { IgnoredClauseBehavior: Remove }
+  ((config as QueryKitConfiguration)?.IgnoredClauseBehavior ?? Remove) == Remove
  • v1.14.2: A clause on a PreventFilter property, or on an unknown property with AllowUnknownProperties, becomes True == True.
  • New (default): The parser removes the clause. An OR keeps only its other side. A group with only removed clauses is removed. If the whole filter is removed, the result is x => True.
  • Opt out: new QueryKitConfiguration(s => s.IgnoredClauseBehavior = IgnoredClauseBehavior.ReplaceWithTrue) gives the v1.14.2 behavior.
  • No config, or a custom IQueryKitConfiguration: gets Remove. These configurations cannot opt out, because the setting is only on QueryKitConfiguration.
  • Why: Under OR, true == true makes the whole filter match every row. So Name == "Ann" || Secret == "s" returns everyone. With Remove, QueryKit drops the clause and keeps the rest of the filter. The result is what the caller asked for, without the prevented part.

Related: #112 asks for a setting to ignore or throw on prevented properties. Throw can join the same enum.

Evidence

With Secret marked PreventFilter, rows Ann, Bob, and Cid, and the filter FirstName == "Ann" || Secret == "s":

v1.14.2 and main:  x => ((x.FirstName == "Ann") OrElse (True == True))   rows [Ann, Bob, Cid]
this PR:           x => (x.FirstName == "Ann")                          rows [Ann]

Under AND, the rows are the same. Only the expression text changes.

Tests, changed from the restore tests:

CustomFilterPropertyTests             expect the clause removed again
PropertyResolverTests (unit, integration)
  config.IgnoredClauseBehavior = Remove lines deleted  -> the default removes
  ..._when_replaced_with_true tests    ReplaceWithTrue set explicitly -> True == True

dotnet test on this branch: all unit and integration tests pass, 0 failures.

Merge Danger

Door: two-way

A later release can change the default back. Consumers can opt out now with one setting.

Blast Radius: consumers

  • Apps where a prevented or unknown clause is under an OR get fewer rows.
  • Apps and tests that compare expression text see True or a shorter expression in place of (True == True).
  • This is not a security change. v1.14.2 returned more rows, but a caller can get all rows with an empty filter.

A clause on a PreventFilter property, or on an unknown property with AllowUnknownProperties, became (true == true). Under an OR, this made the whole filter match every row, so Name == "Ann" || Secret == "s" returned everyone. IgnoredClauseBehavior now defaults to Remove, so QueryKit drops the clause and keeps the rest of the filter. Set it to ReplaceWithTrue to get the v1.14.2 behavior.

BREAKING CHANGE: A prevented or unknown clause is now removed, not replaced with (true == true). Under an OR, the filter returns fewer rows. A filter with only ignored clauses becomes x => True. Set IgnoredClauseBehavior to ReplaceWithTrue to keep the v1.14.2 behavior.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant