Skip to content

feat(exporters): add eventFieldFilter to HTTP exporter#802

Open
RohanKaran wants to merge 5 commits intokubescape:mainfrom
RohanKaran:feature/event-field-filter
Open

feat(exporters): add eventFieldFilter to HTTP exporter#802
RohanKaran wants to merge 5 commits intokubescape:mainfrom
RohanKaran:feature/event-field-filter

Conversation

@RohanKaran
Copy link
Copy Markdown

@RohanKaran RohanKaran commented May 6, 2026

Closes #488

Adds eventFieldFilter to HTTPExporterConfig with allowList and denyList support. Both accept dot-notation paths (e.g. spec.processTree, spec.alerts.severity) including fields nested inside slices. allowList takes precedence when both are set.

"httpExporterConfig": {
  "url": "https://my-backend.example.com",
  "eventFieldFilter": {
    "denyList": ["spec.processTree", "spec.cloudMetadata"]
  }
}

Initially proposed filtering at ExporterBus level, but each exporter serialises differently (HTTP uses JSON paths, stdout uses log field names), so a shared filter would silently no-op for one or the other. Scoped it to HTTPExporterConfig instead, applied as a JSON post-processing step in sendHTTPRequest.

Summary by CodeRabbit

  • New Features

    • Added configurable event field filtering for exported alerts with allowList and denyList using dot-notation to include/exclude nested fields before send.
  • Documentation

    • Expanded HTTP exporter configuration docs with detailed examples, alert bulking settings, event field filter usage, and updated base API URL examples.
  • Tests

    • Added comprehensive tests covering allow/deny precedence, nested/path and slice handling, output encoding, and JSON error cases.

RohanKaran added 3 commits May 6, 2026 23:57
Add EventFieldFilterConfig with allowList and denyList support to
HTTPExporterConfig. The filter is applied as a JSON post-processing
step inside sendHTTPRequest before the payload is sent.

- allowList keeps only the specified fields; denyList removes them
- both support dot notation for nested fields (e.g. spec.processTree)
  and fields inside slices (e.g. spec.alerts.severity)
- allowList takes precedence over denyList when both are set
- large integers (PIDs, nanosecond timestamps) are preserved via
  json.Decoder.UseNumber()
- filter is HTTP-exporter-specific; stdout and other exporters
  are unaffected

Signed-off-by: rohankaran <rohankaran001@gmail.com>
…tering, and rate limits

- change headers field from map to list of key-value pairs
- add support for path, queryParams, maxAlertsPerMinute, and eventFieldFilter
- introduce eventFieldFilter with allowList and denyList for payload field control
- update documentation with examples to reduce payload size or restrict sent fields

Signed-off-by: rohankaran <rohankaran001@gmail.com>
…ieldFilter scope note

- Remove '/v1/runtimealerts' suffix from example URLs for clarity
- Add note clarifying eventFieldFilter applies to all payloads sent through the exporter

Signed-off-by: rohankaran <rohankaran001@gmail.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 6, 2026

Review Change Stack
No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 01fb52c9-6733-418d-8b53-a3068b9cd749

📥 Commits

Reviewing files that changed from the base of the PR and between 6159953 and 85ac441.

📒 Files selected for processing (2)
  • pkg/exporters/field_filter.go
  • pkg/exporters/field_filter_test.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • pkg/exporters/field_filter.go
  • pkg/exporters/field_filter_test.go

📝 Walkthrough

Walkthrough

Adds an EventFieldFilter (configurable allowList or denyList with dot-notation) that prunes or removes fields from JSON alert payloads; integrates the filter into the HTTP exporter pipeline; adds unit tests; and updates configuration documentation and examples.

Changes

Event Field Filtering for HTTP Exports

Layer / File(s) Summary
Data Shape & Configuration
pkg/exporters/field_filter.go
Introduces EventFieldFilterConfig and EventFieldFilter; constructor returns nil when unconfigured and selects allow vs deny mode.
Core Filtering Logic
pkg/exporters/field_filter.go
Implements FilterJSON, applyAllowList, and removePath for dot-notated nested paths and slice-aware traversal; output JSON encoding disables HTML-escaping.
HTTP Exporter Wiring
pkg/exporters/http_exporter.go
Adds EventFieldFilter to HTTPExporterConfig, stores constructed filter on HTTPExporter, and applies it to marshaled JSON before sending HTTP requests.
Tests
pkg/exporters/field_filter_test.go
Unit tests cover nil/empty config behavior, allow/deny precedence, nested-field and slice-item filtering, invalid JSON errors, and no-HTML-escape encoding.
Documentation
docs/CONFIGURATION.md
Adds Event Field Filter documentation and updates HTTP exporter example blocks across Minimal, Full Security, and High-Throughput scenarios (base URL and bulking fields adjusted).

Sequence Diagram

sequenceDiagram
    participant Client as HTTP Exporter
    participant Filter as Field Filter
    participant Sender as HTTP Sender

    Client->>Client: Marshal event to JSON
    Client->>Filter: FilterJSON(jsonPayload)
    alt Has Field Filter Config
        Filter->>Filter: Parse JSON to map
        Filter->>Filter: Apply AllowList OR DenyList
        Filter->>Filter: Recursively filter nested fields and slices
        Filter->>Client: Return filtered JSON bytes
    else No Filter Config
        Filter->>Client: Return original JSON bytes
    end
    Client->>Sender: Send HTTP request with payload
    Sender->>Sender: Apply headers, retries, bulking
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 A rabbit nibbles through fields with care,

keeps what matters, lets extra air.
Allow or deny, dots mark the trail,
slim payloads ship without fail.
Hops of joy for bytes made spare.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.26% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title accurately describes the main change: adding an eventFieldFilter feature to the HTTP exporter configuration.
Linked Issues check ✅ Passed The PR fully implements the requirements from issue #488: configurable field filtering via allowList/denyList in dot notation, field size reduction, user control over exported fields, and a built-in filtering solution.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing the eventFieldFilter feature for the HTTP exporter as specified in the linked issue. No unrelated changes detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
pkg/exporters/field_filter.go (1)

50-72: 💤 Low value

FilterJSON re-marshals with json.Marshal, which applies HTML escaping.

json.Marshal escapes <, >, and & in string values to their Unicode escape sequences (e.g., <\u003c). If alert messages or field values contain these characters, the outgoing payload will differ from what a raw marshal of the original struct would produce. Downstream consumers relying on exact byte content (e.g., signature validation) may see unexpected output.

If this is a concern, swap json.Marshal for json.NewEncoder with SetEscapeHTML(false):

🛠️ Proposed fix
+import "bytes"

-return json.Marshal(m)
+var buf bytes.Buffer
+enc := json.NewEncoder(&buf)
+enc.SetEscapeHTML(false)
+if err := enc.Encode(m); err != nil {
+    return nil, err
+}
+return bytes.TrimRight(buf.Bytes(), "\n"), nil
🤖 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 `@pkg/exporters/field_filter.go` around lines 50 - 72,
EventFieldFilter.FilterJSON currently returns json.Marshal(m) which applies HTML
escaping; replace that marshal with a json.Encoder that disables HTML escaping:
create a bytes.Buffer, use enc := json.NewEncoder(&buf);
enc.SetEscapeHTML(false); encode m with enc.Encode(m) and return the buffer
bytes (trim the trailing newline Encode adds) and nil error; keep the existing
logic using f.useAllow, f.allowSet, f.denySet, applyAllowList and removePath
unchanged.
pkg/exporters/field_filter_test.go (1)

210-250: 💤 Low value

Test coverage looks comprehensive; add a case for slice items with no matching allowed fields.

The existing TestFilterJSON_AllowListSliceField covers the happy path (all items have the allowed field). Consider adding a case where a slice item has none of the allowed fields to verify the current behavior (empty {} is preserved) and make it explicit — especially if the fix from the applyAllowList comment above is applied (empty items would then be omitted).

Also consider a test for FilterJSON returning an error when given invalid JSON bytes, to exercise that error path.

🤖 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 `@pkg/exporters/field_filter_test.go` around lines 210 - 250, Add a new unit
case to TestFilterJSON_AllowListSliceField (or create
TestFilterJSON_AllowListSliceField_EmptyItem) that includes at least one alerts
slice item lacking any allowed fields (e.g., an alert with only "ruleID" and
"severity" removed by AllowList ["kind","spec.alerts.message"]) and assert the
current expected behavior: either an empty map{} is preserved in the output
alerts slice (require.Len/require.NotNil and assert.Empty for that item) or, if
you intend to change behavior via applyAllowList, assert that the item is
omitted (shorter alerts slice), updating expectations accordingly; additionally
add a small test (e.g., TestFilterJSON_InvalidJSON) that calls
EventFieldFilter.FilterJSON with invalid JSON bytes and asserts an error is
returned to cover the error path.
🤖 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 `@pkg/exporters/field_filter.go`:
- Around line 100-110: applyAllowList currently retains empty maps in slices:
when an item is a map[string]any and applyAllowList returns an empty map (no
allowed sub-fields matched), that empty {} is kept in newSlice; change the logic
in applyAllowList (the slice-handling branch in pkg/exporters/field_filter.go)
to skip adding map items that become empty (len(resultingMap)==0) so they are
omitted from newSlice, while still preserving non-map items unchanged and
keeping index-safe behavior (i.e., append only non-empty maps or original
non-map items).

---

Nitpick comments:
In `@pkg/exporters/field_filter_test.go`:
- Around line 210-250: Add a new unit case to TestFilterJSON_AllowListSliceField
(or create TestFilterJSON_AllowListSliceField_EmptyItem) that includes at least
one alerts slice item lacking any allowed fields (e.g., an alert with only
"ruleID" and "severity" removed by AllowList ["kind","spec.alerts.message"]) and
assert the current expected behavior: either an empty map{} is preserved in the
output alerts slice (require.Len/require.NotNil and assert.Empty for that item)
or, if you intend to change behavior via applyAllowList, assert that the item is
omitted (shorter alerts slice), updating expectations accordingly; additionally
add a small test (e.g., TestFilterJSON_InvalidJSON) that calls
EventFieldFilter.FilterJSON with invalid JSON bytes and asserts an error is
returned to cover the error path.

In `@pkg/exporters/field_filter.go`:
- Around line 50-72: EventFieldFilter.FilterJSON currently returns
json.Marshal(m) which applies HTML escaping; replace that marshal with a
json.Encoder that disables HTML escaping: create a bytes.Buffer, use enc :=
json.NewEncoder(&buf); enc.SetEscapeHTML(false); encode m with enc.Encode(m) and
return the buffer bytes (trim the trailing newline Encode adds) and nil error;
keep the existing logic using f.useAllow, f.allowSet, f.denySet, applyAllowList
and removePath unchanged.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: df8b227f-5444-43b7-9b5f-033591c36596

📥 Commits

Reviewing files that changed from the base of the PR and between 2d768cb and 3605799.

📒 Files selected for processing (4)
  • docs/CONFIGURATION.md
  • pkg/exporters/field_filter.go
  • pkg/exporters/field_filter_test.go
  • pkg/exporters/http_exporter.go

Comment thread pkg/exporters/field_filter.go
- Replace json.Marshal with json.NewEncoder + SetEscapeHTML(false) to
  prevent < > & in alert messages being mangled to \u003c etc.
- applyAllowList now omits map items from slices that become empty after
  filtering, instead of keeping phantom {} objects
- Add TestFilterJSON_InvalidJSON_ReturnsError, TestFilterJSON_AllowListSliceField_OmitsEmptyItems,
  TestFilterJSON_NoHTMLEscaping

Signed-off-by: rohankaran <rohankaran001@gmail.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
pkg/exporters/field_filter_test.go (2)

127-127: 💤 Low value

Inconsistent use of []interface{} vs []any.

Line 127 uses []interface{}{"alert1"} while all other tests use []any{...}. In Go 1.18+ any is an alias for interface{}, but the file should be consistent.

🛠️ Proposed fix
-			"alerts":      []interface{}{"alert1"},
+			"alerts":      []any{"alert1"},
🤖 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 `@pkg/exporters/field_filter_test.go` at line 127, The test has an inconsistent
collection type: change the value for the "alerts" key currently written as
[]interface{}{"alert1"} to use the alias []any{"alert1"} so it matches the rest
of the file; locate the occurrence in the test data map within field_filter_test
(the map literal containing "alerts") and replace the type to maintain
consistent use of any across the file.

50-50: ⚡ Quick win

Ignored json.Marshal errors in test setup may mask test construction bugs.

All test functions ignore the error from json.Marshal with _. While json.Marshal rarely fails for map[string]any with plain values, silently discarding the error means a malformed data byte slice (e.g., nil) could flow into FilterJSON and produce a misleading test failure message. Prefer require.NoError to fail fast at the setup step.

🛠️ Proposed fix (representative example from line 50)
-data, _ := json.Marshal(input)
+data, err := json.Marshal(input)
+require.NoError(t, err)

Also applies to: 78-78, 104-104, 131-131, 157-157, 187-187, 226-226, 280-280, 308-308, 334-334, 361-361

🤖 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 `@pkg/exporters/field_filter_test.go` at line 50, Replace all ignored
json.Marshal errors in the test setup (instances like data, _ :=
json.Marshal(input)) with explicit error checks: capture the error (data, err :=
json.Marshal(input)) and call require.NoError(t, err) immediately after so the
test fails fast on marshal failures; apply this change for every occurrence in
the field_filter_test.go file where json.Marshal produces data for calls to
FilterJSON and other test setups.
🤖 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 `@pkg/exporters/field_filter_test.go`:
- Around line 146-169: The test TestFilterJSON_AllowListTakesPrecedence
currently can't prove deny list is ignored because it denies "ruleID" which is
already not allowed; update the test input so at least one field appears in both
AllowList and DenyList (e.g., set AllowList: []string{"message","ruleID"} and
DenyList: []string{"ruleID"}) and include "ruleID" in the marshaled input, then
call f.FilterJSON and assert that output["ruleID"] is present/equals the
original value (i.e., kept) while other non-allowed fields (like "extra") are
nil; keep references to EventFieldFilterConfig, AllowList, DenyList,
TestFilterJSON_AllowListTakesPrecedence, and FilterJSON when making the change.

---

Nitpick comments:
In `@pkg/exporters/field_filter_test.go`:
- Line 127: The test has an inconsistent collection type: change the value for
the "alerts" key currently written as []interface{}{"alert1"} to use the alias
[]any{"alert1"} so it matches the rest of the file; locate the occurrence in the
test data map within field_filter_test (the map literal containing "alerts") and
replace the type to maintain consistent use of any across the file.
- Line 50: Replace all ignored json.Marshal errors in the test setup (instances
like data, _ := json.Marshal(input)) with explicit error checks: capture the
error (data, err := json.Marshal(input)) and call require.NoError(t, err)
immediately after so the test fails fast on marshal failures; apply this change
for every occurrence in the field_filter_test.go file where json.Marshal
produces data for calls to FilterJSON and other test setups.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7d43b721-aa73-4f72-ac9e-a6f16052805b

📥 Commits

Reviewing files that changed from the base of the PR and between 3605799 and 6159953.

📒 Files selected for processing (2)
  • pkg/exporters/field_filter.go
  • pkg/exporters/field_filter_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/exporters/field_filter.go

Comment thread pkg/exporters/field_filter_test.go
- Keep scalar leaf values (string, number, bool) when applying allow list filter
- Add tests to verify scalar values are retained inside nested maps and slices
- Strengthen TestFilterJSON_AllowListTakesPrecedence by including a field in
  both allow and deny lists to actually prove precedence

Signed-off-by: rohankaran <rohankaran001@gmail.com>
@RohanKaran RohanKaran force-pushed the feature/event-field-filter branch from 6159953 to 85ac441 Compare May 8, 2026 17:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

Configure the fields exported by events produced for Runtime Threat Detection ( node-agent)

2 participants