Skip to content

refactor(filters): add filter pkg and middleware for slice architecture BED-8594#2943

Open
mistahj67 wants to merge 5 commits into
mainfrom
BED-8594
Open

refactor(filters): add filter pkg and middleware for slice architecture BED-8594#2943
mistahj67 wants to merge 5 commits into
mainfrom
BED-8594

Conversation

@mistahj67

@mistahj67 mistahj67 commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Description

  • Ports request param filter parsing it's own agnostic package
  • Moves filter parsing into middleware to centralize bespoke boilerplate
  • Stores filter info on the bhctx for later use in db layer
  • Does not update existing filter, should happen dynamically as endpoints are refactored to slice arch

Describe your changes in detail

Motivation and Context

Resolves BED-8594

Why is this change required? What problem does it solve?

How Has This Been Tested?

Please describe in detail how you tested your changes.
Include details of your testing environment, and the tests you ran to
see how your change affects other areas of the code, etc.

Screenshots (optional):

Types of changes

  • Chore (a change that does not modify the application functionality)

Checklist:

Summary by CodeRabbit

  • New Features
    • Added support for filtered API requests via query parameters, validating allowed filter fields and operators.
    • Enabled combining conditions using set operators (AND/OR), with string-aware filter handling.
    • Exposed validated filters to request context and added route-level wiring to enable/disable filtering.
  • Bug Fixes
    • Invalid filter input now returns a clear 400 Bad Request with detailed validation information.
    • When filtering is not enabled, requests pass through unchanged.
  • Tests
    • Added a new test suite covering filter parsing, validation, defaults, skipping ignored parameters, and error messaging.

@mistahj67 mistahj67 self-assigned this Jun 30, 2026
@mistahj67 mistahj67 added the api A pull request containing changes affecting the API code. label Jun 30, 2026
@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: ee9b1a60-b86b-4392-a4ab-eb8c9a9ee337

📥 Commits

Reviewing files that changed from the base of the PR and between 233c3a0 and 1497211.

📒 Files selected for processing (1)
  • cmd/api/src/api/middleware/filters.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • cmd/api/src/api/middleware/filters.go

📝 Walkthrough

Walkthrough

Adds a new filters package for filter operators, validation, and query parsing. The API middleware now parses request filters, stores them on request context, and exposes route wiring for filterable endpoints. A new URI path parameter constant is also added.

Changes

Filters feature

Layer / File(s) Summary
Filter types and validation errors
packages/go/filters/filter.go
Adds FilterOperator constants, ValidationError, ParseFilterOperator, FilterSetOperator, Filter, Filters, FilterableField, and Filterable.
Query parameter parsing
packages/go/filters/parser.go, packages/go/filters/parser_test.go
Implements QueryParameterFilterParser.ParseAndValidate and adds tests for parsing, enrichment, ignored parameters, and error handling.
Middleware, router, context, and constant
cmd/api/src/api/middleware/filters.go, cmd/api/src/api/router/router.go, cmd/api/src/bhctx/bhctx.go, cmd/api/src/api/constant.go
Adds FilterMiddleware and filterErrorMessage, wires Route.WithFilters, stores parsed filters on bhctx.Context.Filters, and adds URIPathVariableAlertWebhookID.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Route
    participant FilterMiddleware
    participant QueryParameterFilterParser
    participant BHContext
    participant Handler
    Client->>Route: HTTP request with query params
    Route->>FilterMiddleware: invoke middleware chain
    FilterMiddleware->>QueryParameterFilterParser: ParseAndValidate(request.URL.Query())
    QueryParameterFilterParser-->>FilterMiddleware: Filters or ValidationError
    alt validation error
        FilterMiddleware-->>Client: 400 Bad Request
    else success
        FilterMiddleware->>BHContext: set Filters
        FilterMiddleware->>Handler: call next handler
    end
Loading

Related Issues: None found in provided information.

Related PRs: None found in provided information.

Suggested labels: enhancement, api

Suggested reviewers: None found in provided information.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main refactor: new filter package and middleware for slice architecture.
Description check ✅ Passed The PR description covers the change, motivation, issue link, type, and checklist, though testing details are minimal.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch BED-8594

Comment @coderabbitai help to get the list of available commands.

@mistahj67 mistahj67 marked this pull request as ready for review July 1, 2026 19:57

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cmd/api/src/api/middleware/filters.go`:
- Around line 38-58: `FilterMiddleware` is rebuilding the query filter parser on
every request instead of once when the middleware is created. Move the
`filters.NewQueryParameterFilterParser(append(model.IgnoreFilters(),
model.AllPaginationQueryParameters()...)...)` construction out of the inner
`http.HandlerFunc` closure in `FilterMiddleware`, so the parser and its regex
compilation happen once per route registration. Keep the request-time logic in
the closure using the prebuilt parser, while preserving the existing
`ParseAndValidate` and `bhctx.Get` behavior.

In `@packages/go/filters/parser.go`:
- Around line 34-39: The QueryParameterFilterParser currently accepts partial
matches from junk input and uses an ambiguous value character class in
NewQueryParameterFilterParser. Update the valuePattern in
QueryParameterFilterParser to anchor the full operator:value expression so
FindStringSubmatch only matches complete filters, and replace the current value
class with an explicit RE2-safe class that matches the documented syntax. Keep
the fix localized to NewQueryParameterFilterParser and the parsing logic that
consumes valuePattern.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: d3a0a5ec-4e3f-4345-86d7-6b1f5dda7441

📥 Commits

Reviewing files that changed from the base of the PR and between aa6e331 and 233c3a0.

📒 Files selected for processing (7)
  • cmd/api/src/api/constant.go
  • cmd/api/src/api/middleware/filters.go
  • cmd/api/src/api/router/router.go
  • cmd/api/src/bhctx/bhctx.go
  • packages/go/filters/filter.go
  • packages/go/filters/parser.go
  • packages/go/filters/parser_test.go

Comment thread cmd/api/src/api/middleware/filters.go
Comment on lines +34 to +39
func NewQueryParameterFilterParser(ignoredParameters ...string) QueryParameterFilterParser {
return QueryParameterFilterParser{
valuePattern: regexp.MustCompile(`([~\w]+):([\w\--_ ]+)`),
ignoredParameters: ignoredParameters,
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

Does Go's regexp package (RE2) treat an escaped hyphen followed by another hyphen inside a character class as forming a byte range, e.g. [\w\--_ ]?

💡 Result:

In Go's regexp package (which is based on the RE2 engine), the behavior of the expression [\w--_ ] inside a character class is as follows: The backslash \ before the first hyphen acts as an escape, treating it as a literal hyphen character within the character class [1][2]. Consequently, it does not function as a range operator. When the RE2 parser encounters the sequence -, it consumes the hyphen as a literal character element [2][3]. The subsequent hyphen in your expression (--) is then interpreted as a range operator because it is placed between the literal hyphen (from -) and the underscore character [4][5]. Therefore, the expression [\w-- ] expands to include: 1. All characters matched by \w (the word characters: [0-9A-Za-z_]) [6][7]. 2. A literal hyphen (the result of the - escape) [2]. 3. The range of characters from hyphen to underscore (hyphen through underscore, inclusive) [5]. 4. The space character [6]. Because the range --_ spans characters in the ASCII table where the hyphen (ASCII 45) comes before the underscore (ASCII 95), this effectively adds all characters between those two points (including punctuation like slash, colon, etc.) to the character class [6][5]. Using an escape before a hyphen is a reliable way to include a literal hyphen in a character class without triggering range behavior [2].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the parser and its tests around the regex/matching behavior.
git ls-files packages/go/filters/parser.go packages/go/filters/parser_test.go
echo '--- parser.go ---'
cat -n packages/go/filters/parser.go
echo '--- parser_test.go ---'
cat -n packages/go/filters/parser_test.go

# Programmatic probe for the regex semantics in Go.
python3 - <<'PY'
import re
pattern = r'([~\w]+):([\w\--_ ]+)'
samples = [
    "eq:foo",
    "eq:foo-bar",
    "eq:foo/bar",
    "junk eq:foo",
    "eq:foo:bar",
]
print("Python-re module is not Go RE2, so this is only a placeholder for structure.")
print("Use the Go regexp docs / repo tests for the actual semantics.")
for s in samples:
    m = re.search(pattern, s)
    print(s, "=>", m.groups() if m else None)
PY

Repository: SpecterOps/BloodHound

Length of output: 12447


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Search for documented/expected filter value syntax beyond parser_test.go.
rg -n "auth\.value|hello world|QueryParameterFilterParser|ParseAndValidate|operator:value|filter" packages/go -g '!**/*vendor*'

# Inspect any additional parser-related tests or docs in the repository.
fd -a -t f 'README.md' . packages/go
fd -a -t f '*filter*' packages/go

Repository: SpecterOps/BloodHound

Length of output: 50377


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- packages/go/openapi/src/schemas/api.params.predicate.filter.string.yaml ---'
cat -n packages/go/openapi/src/schemas/api.params.predicate.filter.string.yaml

echo '--- packages/go/openapi/src/paths/config.config.yaml ---'
cat -n packages/go/openapi/src/paths/config.config.yaml

echo '--- parser test excerpt ---'
sed -n '54,90p' packages/go/filters/parser_test.go

Repository: SpecterOps/BloodHound

Length of output: 6379


Reject partial filter matches in packages/go/filters/parser.go
FindStringSubmatch can parse a valid operator:value substring inside junk input (junk eq:foo), and [\w\--_ ] relies on an unintended RE2 range. Anchor the regex and use an explicit value class that matches the documented syntax.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/go/filters/parser.go` around lines 34 - 39, The
QueryParameterFilterParser currently accepts partial matches from junk input and
uses an ambiguous value character class in NewQueryParameterFilterParser. Update
the valuePattern in QueryParameterFilterParser to anchor the full operator:value
expression so FindStringSubmatch only matches complete filters, and replace the
current value class with an explicit RE2-safe class that matches the documented
syntax. Keep the fix localized to NewQueryParameterFilterParser and the parsing
logic that consumes valuePattern.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api A pull request containing changes affecting the API code.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant