feat: falco integration #3011

Merged
mfreeman451 merged 3 commits from refs/pull/3011/head into staging 2026-03-03 08:21:17 +00:00
mfreeman451 commented 2026-03-03 06:50:13 +00:00 (Migrated from github.com)
Owner

Imported from GitHub pull request.

Original GitHub pull request: #2986
Original author: @mfreeman451
Original URL: https://github.com/carverauto/serviceradar/pull/2986
Original created: 2026-03-03T06:50:13Z
Original updated: 2026-03-03T08:21:19Z
Original head: carverauto/serviceradar:2985-feat-falco-integration
Original base: staging
Original merged: 2026-03-03T08:21:17Z by @mfreeman451

IMPORTANT: Please sign the Developer Certificate of Origin

Thank you for your contribution to ServiceRadar. Please note, when contributing, the developer must include
a DCO sign-off statement indicating the DCO acceptance in one commit message. Here
is an example DCO Signed-off-by line in a commit message:

Signed-off-by: J. Doe <j.doe@domain.com>

Describe your changes

Code checklist before requesting a review

  • I have signed the DCO?
  • The build completes without errors?
  • All tests are passing when running make test?
Imported from GitHub pull request. Original GitHub pull request: #2986 Original author: @mfreeman451 Original URL: https://github.com/carverauto/serviceradar/pull/2986 Original created: 2026-03-03T06:50:13Z Original updated: 2026-03-03T08:21:19Z Original head: carverauto/serviceradar:2985-feat-falco-integration Original base: staging Original merged: 2026-03-03T08:21:17Z by @mfreeman451 --- ## IMPORTANT: Please sign the Developer Certificate of Origin Thank you for your contribution to ServiceRadar. Please note, when contributing, the developer must include a [DCO sign-off statement]( https://developercertificate.org/) indicating the DCO acceptance in one commit message. Here is an example DCO Signed-off-by line in a commit message: ``` Signed-off-by: J. Doe <j.doe@domain.com> ``` ## Describe your changes ## Issue ticket number and link ## Code checklist before requesting a review - [ ] I have signed the DCO? - [ ] The build completes without errors? - [ ] All tests are passing when running make test?
qodo-code-review[bot] commented 2026-03-03 06:50:31 +00:00 (Migrated from github.com)
Author
Owner

Imported GitHub PR comment.

Original author: @qodo-code-review[bot]
Original URL: https://github.com/carverauto/serviceradar/pull/2986#issuecomment-3989043307
Original created: 2026-03-03T06:50:31Z

Review Summary by Qodo

Add Falco runtime security event consumer to EventWriter pipeline

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Add Falco runtime security event ingestion to EventWriter Broadway pipeline
• Normalize Falco payloads into OCSF Event Log Activity rows in ocsf_events
• Map Falco priority levels to OCSF severity and status using deterministic policy
• Preserve original Falco context (rule, hostname, output_fields, tags) for investigation
• Route falco.> subjects through dedicated processor with idempotent deduplication
Diagram
flowchart LR
  A["Falco Events<br/>falco.> subjects"] -->|JetStream| B["EventWriter<br/>Broadway Pipeline"]
  B -->|Route falco.*| C["FalcoEvents<br/>Processor"]
  C -->|Normalize to OCSF| D["ocsf_events<br/>Database Table"]
  D -->|PubSub + Rules| E["Events UI &<br/>Alert Workflows"]
Grey Divider

File Changes

1. elixir/serviceradar_core/lib/serviceradar/event_writer/processors/falco_events.ex ✨ Enhancement +291/-0

New Falco event processor with OCSF normalization

elixir/serviceradar_core/lib/serviceradar/event_writer/processors/falco_events.ex


2. elixir/serviceradar_core/config/runtime.exs ⚙️ Configuration changes +8/-0

Add Falco stream configuration to production environment

elixir/serviceradar_core/config/runtime.exs


3. elixir/serviceradar_core/lib/serviceradar/event_writer/config.ex ⚙️ Configuration changes +14/-0

Add Falco stream defaults to EventWriter configuration

elixir/serviceradar_core/lib/serviceradar/event_writer/config.ex


View more (8)
4. elixir/serviceradar_core/lib/serviceradar/event_writer/pipeline.ex ✨ Enhancement +5/-0

Add Falco subject routing and processor mapping

elixir/serviceradar_core/lib/serviceradar/event_writer/pipeline.ex


5. elixir/serviceradar_core/test/serviceradar/event_writer/processors/falco_events_test.exs 🧪 Tests +132/-0

Comprehensive test suite for Falco event processing

elixir/serviceradar_core/test/serviceradar/event_writer/processors/falco_events_test.exs


6. elixir/serviceradar_core/test/serviceradar/event_writer/config_test.exs 🧪 Tests +1/-0

Verify Falco stream in default configuration

elixir/serviceradar_core/test/serviceradar/event_writer/config_test.exs


7. docs/docs/falco-integration.md 📝 Documentation +8/-1

Document EventWriter persistence and verification steps

docs/docs/falco-integration.md


8. openspec/changes/add-falco-ocsf-event-consumer/design.md 📝 Documentation +95/-0

Design document for Falco OCSF event consumer

openspec/changes/add-falco-ocsf-event-consumer/design.md


9. openspec/changes/add-falco-ocsf-event-consumer/proposal.md 📝 Documentation +37/-0

Proposal for Falco runtime security event ingestion

openspec/changes/add-falco-ocsf-event-consumer/proposal.md


10. openspec/changes/add-falco-ocsf-event-consumer/specs/observability-signals/spec.md 📝 Documentation +72/-0

Requirements and scenarios for Falco event persistence

openspec/changes/add-falco-ocsf-event-consumer/specs/observability-signals/spec.md


11. openspec/changes/add-falco-ocsf-event-consumer/tasks.md 📝 Documentation +30/-0

Implementation tasks and completion checklist

openspec/changes/add-falco-ocsf-event-consumer/tasks.md


Grey Divider

Qodo Logo

Imported GitHub PR comment. Original author: @qodo-code-review[bot] Original URL: https://github.com/carverauto/serviceradar/pull/2986#issuecomment-3989043307 Original created: 2026-03-03T06:50:31Z --- <h3>Review Summary by Qodo</h3> Add Falco runtime security event consumer to EventWriter pipeline <code>✨ Enhancement</code> <img src="https://www.qodo.ai/wp-content/uploads/2025/11/light-grey-line.svg" height="10%" alt="Grey Divider"> <h3>Walkthroughs</h3> <details open> <summary>Description</summary> <br/> <pre> • Add Falco runtime security event ingestion to EventWriter Broadway pipeline • Normalize Falco payloads into OCSF Event Log Activity rows in <b><i>ocsf_events</i></b> • Map Falco priority levels to OCSF severity and status using deterministic policy • Preserve original Falco context (rule, hostname, output_fields, tags) for investigation • Route <b><i>falco.&gt;</i></b> subjects through dedicated processor with idempotent deduplication </pre> </details> <details> <summary>Diagram</summary> <br/> > ```mermaid flowchart LR A["Falco Events<br/>falco.> subjects"] -->|JetStream| B["EventWriter<br/>Broadway Pipeline"] B -->|Route falco.*| C["FalcoEvents<br/>Processor"] C -->|Normalize to OCSF| D["ocsf_events<br/>Database Table"] D -->|PubSub + Rules| E["Events UI &<br/>Alert Workflows"] ``` </details> <img src="https://www.qodo.ai/wp-content/uploads/2025/11/light-grey-line.svg" height="10%" alt="Grey Divider"> <h3>File Changes</h3> <details> <summary>1. elixir/serviceradar_core/lib/serviceradar/event_writer/processors/falco_events.ex <code>✨ Enhancement</code> <code> +291/-0 </code> </summary> <br/> >New Falco event processor with OCSF normalization > ><a href='https://github.com/carverauto/serviceradar/pull/2986/files#diff-369e8404a0e84523719981fe67eac4f7504448e2e40843f6439882cd7b44703a'> elixir/serviceradar_core/lib/serviceradar/event_writer/processors/falco_events.ex </a> <hr/> </details> <details> <summary>2. elixir/serviceradar_core/config/runtime.exs <code>⚙️ Configuration changes</code> <code> +8/-0 </code> </summary> <br/> >Add Falco stream configuration to production environment > ><a href='https://github.com/carverauto/serviceradar/pull/2986/files#diff-5d045e2af9f15590a9745058e25a00380ad7a2cc363d0a9934715bd11ea8eef3'> elixir/serviceradar_core/config/runtime.exs </a> <hr/> </details> <details> <summary>3. elixir/serviceradar_core/lib/serviceradar/event_writer/config.ex <code>⚙️ Configuration changes</code> <code> +14/-0 </code> </summary> <br/> >Add Falco stream defaults to EventWriter configuration > ><a href='https://github.com/carverauto/serviceradar/pull/2986/files#diff-c744d27fc45aecf0680acf0deb0365e663f9816f6fd9d44eab2f7b97153d8897'> elixir/serviceradar_core/lib/serviceradar/event_writer/config.ex </a> <hr/> </details> <details><summary><ins><strong>View more (8)</strong></ins></summary><br/> <details> <summary>4. elixir/serviceradar_core/lib/serviceradar/event_writer/pipeline.ex <code>✨ Enhancement</code> <code> +5/-0 </code> </summary> <br/> >Add Falco subject routing and processor mapping > ><a href='https://github.com/carverauto/serviceradar/pull/2986/files#diff-876e8049c9abc69fbc9af55c1b159011b8a52e0fe55db77281a14480fcd47548'> elixir/serviceradar_core/lib/serviceradar/event_writer/pipeline.ex </a> <hr/> </details> <details> <summary>5. elixir/serviceradar_core/test/serviceradar/event_writer/processors/falco_events_test.exs <code>🧪 Tests</code> <code> +132/-0 </code> </summary> <br/> >Comprehensive test suite for Falco event processing > ><a href='https://github.com/carverauto/serviceradar/pull/2986/files#diff-66fc7b0e578911b2b7937e6e6b57c4cf6998d2784885e76830f56f3fe5dc82c7'> elixir/serviceradar_core/test/serviceradar/event_writer/processors/falco_events_test.exs </a> <hr/> </details> <details> <summary>6. elixir/serviceradar_core/test/serviceradar/event_writer/config_test.exs <code>🧪 Tests</code> <code> +1/-0 </code> </summary> <br/> >Verify Falco stream in default configuration > ><a href='https://github.com/carverauto/serviceradar/pull/2986/files#diff-0e6ed3b49f9fc318654d2f8652d4bc584b8c2adca89b899b9d0178afdee404ca'> elixir/serviceradar_core/test/serviceradar/event_writer/config_test.exs </a> <hr/> </details> <details> <summary>7. docs/docs/falco-integration.md <code>📝 Documentation</code> <code> +8/-1 </code> </summary> <br/> >Document EventWriter persistence and verification steps > ><a href='https://github.com/carverauto/serviceradar/pull/2986/files#diff-e0ebafd5cc5f498253da37160323fbe8156f7a35ac629e75ab71c31c3b323d7a'> docs/docs/falco-integration.md </a> <hr/> </details> <details> <summary>8. openspec/changes/add-falco-ocsf-event-consumer/design.md <code>📝 Documentation</code> <code> +95/-0 </code> </summary> <br/> >Design document for Falco OCSF event consumer > ><a href='https://github.com/carverauto/serviceradar/pull/2986/files#diff-07d24b442f9aabc5cb9542271f403ed018f275286d5a59d95c070dce6b9edb94'> openspec/changes/add-falco-ocsf-event-consumer/design.md </a> <hr/> </details> <details> <summary>9. openspec/changes/add-falco-ocsf-event-consumer/proposal.md <code>📝 Documentation</code> <code> +37/-0 </code> </summary> <br/> >Proposal for Falco runtime security event ingestion > ><a href='https://github.com/carverauto/serviceradar/pull/2986/files#diff-fffc3dd8f23c8f1cea4fccf4e9d5c2a7229e66e1a7cea836da41c6d4beca0dc2'> openspec/changes/add-falco-ocsf-event-consumer/proposal.md </a> <hr/> </details> <details> <summary>10. openspec/changes/add-falco-ocsf-event-consumer/specs/observability-signals/spec.md <code>📝 Documentation</code> <code> +72/-0 </code> </summary> <br/> >Requirements and scenarios for Falco event persistence > ><a href='https://github.com/carverauto/serviceradar/pull/2986/files#diff-be3fb3ca7b141370a816e86784055a4684df2cc2077b7f1dee6386e36b82366f'> openspec/changes/add-falco-ocsf-event-consumer/specs/observability-signals/spec.md </a> <hr/> </details> <details> <summary>11. openspec/changes/add-falco-ocsf-event-consumer/tasks.md <code>📝 Documentation</code> <code> +30/-0 </code> </summary> <br/> >Implementation tasks and completion checklist > ><a href='https://github.com/carverauto/serviceradar/pull/2986/files#diff-84f83c5e361f49ff0debb83eeea2ba67d4b7f01e23713a88734d409aa6c43630'> openspec/changes/add-falco-ocsf-event-consumer/tasks.md </a> <hr/> </details> </details> <img src="https://www.qodo.ai/wp-content/uploads/2025/11/light-grey-line.svg" height="10%" alt="Grey Divider"> <a href="https://www.qodo.ai"><img src="https://www.qodo.ai/wp-content/uploads/2025/03/qodo-logo.svg" width="80" alt="Qodo Logo"></a>
qodo-code-review[bot] commented 2026-03-03 06:50:32 +00:00 (Migrated from github.com)
Author
Owner

Imported GitHub PR comment.

Original author: @qodo-code-review[bot]
Original URL: https://github.com/carverauto/serviceradar/pull/2986#issuecomment-3989043436
Original created: 2026-03-03T06:50:32Z

Code Review by Qodo

🐞 Bugs (3) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider
Action required
1. Falco subject mismatch 🐞 Bug ✓ Correctness
Description
This PR subscribes/routes Falco as falco.* on stream falco_events, but existing Falcosidekick
enrollment defaults and NATS permissions publish to events.falco.* (e.g., events.falco.raw). If
publishers follow the existing defaults, Falco events will be routed to the :events processor and
dropped (acknowledged) instead of persisted.
Code

elixir/serviceradar_core/config/runtime.exs[R467-474]

+        %{
+          name: "FALCO",
+          stream_name: "falco_events",
+          subject: "falco.>",
+          processor: ServiceRadar.EventWriter.Processors.FalcoEvents,
+          batch_size: 100,
+          batch_timeout: 1_000
+        },
Evidence
EventWriter is configured to consume falco.> and the pipeline only routes subjects starting with
falco. into the Falco processor. However, the provisioning/enrollment code for :falcosidekick
explicitly configures/publishes under events.falco.*, which the pipeline routes to the :events
batcher whose processor requires OCSF-shaped fields and returns nil otherwise—so raw Falco JSON
would be dropped/acked.

elixir/serviceradar_core/config/runtime.exs[467-474]
elixir/serviceradar_core/lib/serviceradar/event_writer/pipeline.ex[190-207]
elixir/serviceradar_core/lib/serviceradar/event_writer/pipeline.ex[239-246]
elixir/serviceradar_core/lib/serviceradar/edge/workers/provision_collector_worker.ex[214-218]
elixir/web-ng/lib/serviceradar_web_ng_web/controllers/api/collector_enroll_controller.ex[292-297]
elixir/serviceradar_core/lib/serviceradar/event_writer/processors/events.ex[72-124]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Falco ingestion is wired to `falco.*` subjects, but the system’s Falcosidekick enrollment/permission defaults publish to `events.falco.*`. With current defaults, Falco messages will not reach the new Falco processor and will likely be dropped/acked.
### Issue Context
- The EventWriter pipeline routes by subject prefix.
- Falcosidekick enrollment defaults define the publish subject used by deployed collectors.
### Fix Focus Areas
- elixir/serviceradar_core/lib/serviceradar/event_writer/pipeline.ex[190-246]
- elixir/serviceradar_core/config/runtime.exs[458-476]
- elixir/serviceradar_core/lib/serviceradar/event_writer/config.ex[10-34]
- elixir/serviceradar_core/lib/serviceradar/event_writer/config.ex[130-147]
- elixir/serviceradar_core/lib/serviceradar/edge/workers/provision_collector_worker.ex[214-218]
- elixir/web-ng/lib/serviceradar_web_ng_web/controllers/api/collector_enroll_controller.ex[292-297]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Duplicates trigger alerts🐞 Bug ✓ Correctness
Description
Stateful alert rules are evaluated on all parsed rows even when insert_all skips duplicates
(on_conflict: :nothing). This can inflate counters and re-fire alerts on JetStream redeliveries
even though no new DB rows were inserted.
Code

elixir/serviceradar_core/lib/serviceradar/event_writer/processors/falco_events.ex[R46-53]

+      case ServiceRadar.Repo.insert_all(table_name(), rows,
+             on_conflict: :nothing,
+             returning: false
+           ) do
+        {count, _} ->
+          maybe_evaluate_stateful_rules(rows)
+          EventsPubSub.broadcast_event(%{count: count})
+          {:ok, count}
Evidence
FalcoEvents calls maybe_evaluate_stateful_rules(rows) regardless of how many rows were actually
inserted, while insert_all is configured not to return inserted rows and can silently skip
conflicts. StatefulAlertEngine iterates over each provided event without deduplication, so
duplicates/redeliveries can be counted multiple times.

elixir/serviceradar_core/lib/serviceradar/event_writer/processors/falco_events.ex[46-53]
elixir/serviceradar_core/lib/serviceradar/observability/stateful_alert_engine.ex[68-73]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
FalcoEvents evaluates StatefulAlertEngine for every parsed row even when the DB insert skipped some rows as duplicates. This can cause false positives / repeated alert firing under JetStream redelivery.
### Issue Context
`insert_all` uses `on_conflict: :nothing` and `returning: false`, so the code currently has no way to know which rows were inserted.
### Fix Focus Areas
- elixir/serviceradar_core/lib/serviceradar/event_writer/processors/falco_events.ex[35-55]
- elixir/serviceradar_core/lib/serviceradar/observability/stateful_alert_engine.ex[68-73]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended
3. Unstable time breaks dedupe🐞 Bug ⛯ Reliability
Description
ocsf_events uses a composite primary key (time, id), but FalcoEvents falls back to a
per-delivery received_at timestamp when payload time is missing. On JetStream redelivery (or
malformed timestamps), the same deterministic id can be inserted multiple times because time
changes across deliveries.
Code

elixir/serviceradar_core/lib/serviceradar/event_writer/processors/falco_events.ex[R221-223]

+  defp parse_event_time(nil, %DateTime{} = received_at), do: received_at
+  defp parse_event_time(nil, _received_at), do: DateTime.utc_now()
+  defp parse_event_time(value, _received_at), do: FieldParser.parse_timestamp(value)
Evidence
FalcoEvents uses metadata[:received_at] (or DateTime.utc_now/0) when payload time is nil, and
Producer sets received_at to DateTime.utc_now/0 on each delivery. Since the table primary key is
(time, id), using a changing fallback time defeats on_conflict: :nothing for redeliveries when
time is absent/invalid.

elixir/serviceradar_core/lib/serviceradar/event_writer/processors/falco_events.ex[221-223]
elixir/serviceradar_core/lib/serviceradar/event_writer/producer.ex[145-152]
elixir/serviceradar_core/priv/repo/migrations/20260203120000_create_ocsf_events.exs[14-45]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
FalcoEvents uses a per-delivery timestamp fallback (`received_at` / `utc_now`) when the Falco payload lacks a usable `time`. Because `ocsf_events` deduplicates on `(time,id)`, redeliveries can produce duplicate rows even with deterministic IDs.
### Issue Context
Producer currently sets `received_at` using `DateTime.utc_now()` at delivery time.
### Fix Focus Areas
- elixir/serviceradar_core/lib/serviceradar/event_writer/processors/falco_events.ex[205-223]
- elixir/serviceradar_core/lib/serviceradar/event_writer/producer.ex[140-158]
- elixir/serviceradar_core/priv/repo/migrations/20260203120000_create_ocsf_events.exs[14-45]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider
ⓘ The new review experience is currently in Beta. Learn more
Grey Divider

Qodo Logo

Imported GitHub PR comment. Original author: @qodo-code-review[bot] Original URL: https://github.com/carverauto/serviceradar/pull/2986#issuecomment-3989043436 Original created: 2026-03-03T06:50:32Z --- <h3>Code Review by Qodo</h3> <code>🐞 Bugs (3)</code> <code>📘 Rule violations (0)</code> <code>📎 Requirement gaps (0)</code> <img src="https://www.qodo.ai/wp-content/uploads/2025/11/light-grey-line.svg" height="10%" alt="Grey Divider"> <br/> <img src="https://www.qodo.ai/wp-content/uploads/2026/01/action-required.png" height="20" alt="Action required"> <details> <summary> 1. Falco subject mismatch <code>🐞 Bug</code> <code>✓ Correctness</code></summary> <br/> > <details open> ><summary>Description</summary> ><br/> > ><pre> >This PR subscribes/routes Falco as <b><i>falco.*</i></b> on stream <b><i>falco_events</i></b>, but existing Falcosidekick >enrollment defaults and NATS permissions publish to <b><i>events.falco.*</i></b> (e.g., <b><i>events.falco.raw</i></b>). If >publishers follow the existing defaults, Falco events will be routed to the <b><i>:events</i></b> processor and >dropped (acknowledged) instead of persisted. ></pre> ></details> > <details open> ><summary>Code</summary> ><br/> > ><code>[elixir/serviceradar_core/config/runtime.exs[R467-474]](https://github.com/carverauto/serviceradar/pull/2986/files#diff-5d045e2af9f15590a9745058e25a00380ad7a2cc363d0a9934715bd11ea8eef3R467-R474)</code> > >```diff >+ %{ >+ name: "FALCO", >+ stream_name: "falco_events", >+ subject: "falco.>", >+ processor: ServiceRadar.EventWriter.Processors.FalcoEvents, >+ batch_size: 100, >+ batch_timeout: 1_000 >+ }, >``` ></details> > <details > ><summary>Evidence</summary> ><br/> > ><pre> >EventWriter is configured to consume <b><i>falco.&gt;</i></b> and the pipeline only routes subjects starting with ><b><i>falco.</i></b> into the Falco processor. However, the provisioning/enrollment code for <b><i>:falcosidekick</i></b> >explicitly configures/publishes under <b><i>events.falco.*</i></b>, which the pipeline routes to the <b><i>:events</i></b> >batcher whose processor requires OCSF-shaped fields and returns nil otherwise—so raw Falco JSON >would be dropped/acked. ></pre> > > <code>[elixir/serviceradar_core/config/runtime.exs[467-474]](https://github.com/carverauto/serviceradar/blob/0218b614c6df86bde8f84e8f6cc52042833d5ed4/elixir/serviceradar_core/config/runtime.exs/#L467-L474)</code> > <code>[elixir/serviceradar_core/lib/serviceradar/event_writer/pipeline.ex[190-207]](https://github.com/carverauto/serviceradar/blob/0218b614c6df86bde8f84e8f6cc52042833d5ed4/elixir/serviceradar_core/lib/serviceradar/event_writer/pipeline.ex/#L190-L207)</code> > <code>[elixir/serviceradar_core/lib/serviceradar/event_writer/pipeline.ex[239-246]](https://github.com/carverauto/serviceradar/blob/0218b614c6df86bde8f84e8f6cc52042833d5ed4/elixir/serviceradar_core/lib/serviceradar/event_writer/pipeline.ex/#L239-L246)</code> > <code>[elixir/serviceradar_core/lib/serviceradar/edge/workers/provision_collector_worker.ex[214-218]](https://github.com/carverauto/serviceradar/blob/0218b614c6df86bde8f84e8f6cc52042833d5ed4/elixir/serviceradar_core/lib/serviceradar/edge/workers/provision_collector_worker.ex/#L214-L218)</code> > <code>[elixir/web-ng/lib/serviceradar_web_ng_web/controllers/api/collector_enroll_controller.ex[292-297]](https://github.com/carverauto/serviceradar/blob/0218b614c6df86bde8f84e8f6cc52042833d5ed4/elixir/web-ng/lib/serviceradar_web_ng_web/controllers/api/collector_enroll_controller.ex/#L292-L297)</code> > <code>[elixir/serviceradar_core/lib/serviceradar/event_writer/processors/events.ex[72-124]](https://github.com/carverauto/serviceradar/blob/0218b614c6df86bde8f84e8f6cc52042833d5ed4/elixir/serviceradar_core/lib/serviceradar/event_writer/processors/events.ex/#L72-L124)</code> ></details> > <details> ><summary>Agent prompt</summary> ><br/> > >``` >The issue below was found during a code review. Follow the provided context and guidance below and implement a solution > >## Issue description >Falco ingestion is wired to `falco.*` subjects, but the system’s Falcosidekick enrollment/permission defaults publish to `events.falco.*`. With current defaults, Falco messages will not reach the new Falco processor and will likely be dropped/acked. >### Issue Context >- The EventWriter pipeline routes by subject prefix. >- Falcosidekick enrollment defaults define the publish subject used by deployed collectors. >### Fix Focus Areas >- elixir/serviceradar_core/lib/serviceradar/event_writer/pipeline.ex[190-246] >- elixir/serviceradar_core/config/runtime.exs[458-476] >- elixir/serviceradar_core/lib/serviceradar/event_writer/config.ex[10-34] >- elixir/serviceradar_core/lib/serviceradar/event_writer/config.ex[130-147] >- elixir/serviceradar_core/lib/serviceradar/edge/workers/provision_collector_worker.ex[214-218] >- elixir/web-ng/lib/serviceradar_web_ng_web/controllers/api/collector_enroll_controller.ex[292-297] >``` > <code>ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools</code> ></details> <hr/> </details> <details> <summary> 2. <s>Duplicates trigger alerts</s> ☑ <code>🐞 Bug</code> <code>✓ Correctness</code></summary> <br/> > <details open> ><summary>Description</summary> ><br/> > ><pre> >Stateful alert rules are evaluated on all parsed rows even when <b><i>insert_all</i></b> skips duplicates >(<b><i>on_conflict: :nothing</i></b>). This can inflate counters and re-fire alerts on JetStream redeliveries >even though no new DB rows were inserted. ></pre> ></details> > <details open> ><summary>Code</summary> ><br/> > ><code>[elixir/serviceradar_core/lib/serviceradar/event_writer/processors/falco_events.ex[R46-53]](https://github.com/carverauto/serviceradar/pull/2986/files#diff-369e8404a0e84523719981fe67eac4f7504448e2e40843f6439882cd7b44703aR46-R53)</code> > >```diff >+ case ServiceRadar.Repo.insert_all(table_name(), rows, >+ on_conflict: :nothing, >+ returning: false >+ ) do >+ {count, _} -> >+ maybe_evaluate_stateful_rules(rows) >+ EventsPubSub.broadcast_event(%{count: count}) >+ {:ok, count} >``` ></details> > <details > ><summary>Evidence</summary> ><br/> > ><pre> >FalcoEvents calls <b><i>maybe_evaluate_stateful_rules(rows)</i></b> regardless of how many rows were actually >inserted, while <b><i>insert_all</i></b> is configured not to return inserted rows and can silently skip >conflicts. StatefulAlertEngine iterates over each provided event without deduplication, so >duplicates/redeliveries can be counted multiple times. ></pre> > > <code>[elixir/serviceradar_core/lib/serviceradar/event_writer/processors/falco_events.ex[46-53]](https://github.com/carverauto/serviceradar/blob/0218b614c6df86bde8f84e8f6cc52042833d5ed4/elixir/serviceradar_core/lib/serviceradar/event_writer/processors/falco_events.ex/#L46-L53)</code> > <code>[elixir/serviceradar_core/lib/serviceradar/observability/stateful_alert_engine.ex[68-73]](https://github.com/carverauto/serviceradar/blob/0218b614c6df86bde8f84e8f6cc52042833d5ed4/elixir/serviceradar_core/lib/serviceradar/observability/stateful_alert_engine.ex/#L68-L73)</code> ></details> > <details> ><summary>Agent prompt</summary> ><br/> > >``` >The issue below was found during a code review. Follow the provided context and guidance below and implement a solution > >## Issue description >FalcoEvents evaluates StatefulAlertEngine for every parsed row even when the DB insert skipped some rows as duplicates. This can cause false positives / repeated alert firing under JetStream redelivery. >### Issue Context >`insert_all` uses `on_conflict: :nothing` and `returning: false`, so the code currently has no way to know which rows were inserted. >### Fix Focus Areas >- elixir/serviceradar_core/lib/serviceradar/event_writer/processors/falco_events.ex[35-55] >- elixir/serviceradar_core/lib/serviceradar/observability/stateful_alert_engine.ex[68-73] >``` > <code>ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools</code> ></details> <hr/> </details> <br/> <img src="https://www.qodo.ai/wp-content/uploads/2026/01/review-recommended.png" height="20" alt="Remediation recommended"> <details> <summary> 3. <s>Unstable time breaks dedupe</s> ☑ <code>🐞 Bug</code> <code>⛯ Reliability</code></summary> <br/> > <details open> ><summary>Description</summary> ><br/> > ><pre> ><b><i>ocsf_events</i></b> uses a composite primary key <b><i>(time, id)</i></b>, but FalcoEvents falls back to a >per-delivery <b><i>received_at</i></b> timestamp when payload time is missing. On JetStream redelivery (or >malformed timestamps), the same deterministic <b><i>id</i></b> can be inserted multiple times because <b><i>time</i></b> >changes across deliveries. ></pre> ></details> > <details open> ><summary>Code</summary> ><br/> > ><code>[elixir/serviceradar_core/lib/serviceradar/event_writer/processors/falco_events.ex[R221-223]](https://github.com/carverauto/serviceradar/pull/2986/files#diff-369e8404a0e84523719981fe67eac4f7504448e2e40843f6439882cd7b44703aR221-R223)</code> > >```diff >+ defp parse_event_time(nil, %DateTime{} = received_at), do: received_at >+ defp parse_event_time(nil, _received_at), do: DateTime.utc_now() >+ defp parse_event_time(value, _received_at), do: FieldParser.parse_timestamp(value) >``` ></details> > <details > ><summary>Evidence</summary> ><br/> > ><pre> >FalcoEvents uses <b><i>metadata[:received_at]</i></b> (or <b><i>DateTime.utc_now/0</i></b>) when payload time is nil, and >Producer sets <b><i>received_at</i></b> to <b><i>DateTime.utc_now/0</i></b> on each delivery. Since the table primary key is ><b><i>(time, id)</i></b>, using a changing fallback time defeats <b><i>on_conflict: :nothing</i></b> for redeliveries when >time is absent/invalid. ></pre> > > <code>[elixir/serviceradar_core/lib/serviceradar/event_writer/processors/falco_events.ex[221-223]](https://github.com/carverauto/serviceradar/blob/0218b614c6df86bde8f84e8f6cc52042833d5ed4/elixir/serviceradar_core/lib/serviceradar/event_writer/processors/falco_events.ex/#L221-L223)</code> > <code>[elixir/serviceradar_core/lib/serviceradar/event_writer/producer.ex[145-152]](https://github.com/carverauto/serviceradar/blob/0218b614c6df86bde8f84e8f6cc52042833d5ed4/elixir/serviceradar_core/lib/serviceradar/event_writer/producer.ex/#L145-L152)</code> > <code>[elixir/serviceradar_core/priv/repo/migrations/20260203120000_create_ocsf_events.exs[14-45]](https://github.com/carverauto/serviceradar/blob/0218b614c6df86bde8f84e8f6cc52042833d5ed4/elixir/serviceradar_core/priv/repo/migrations/20260203120000_create_ocsf_events.exs/#L14-L45)</code> ></details> > <details> ><summary>Agent prompt</summary> ><br/> > >``` >The issue below was found during a code review. Follow the provided context and guidance below and implement a solution > >## Issue description >FalcoEvents uses a per-delivery timestamp fallback (`received_at` / `utc_now`) when the Falco payload lacks a usable `time`. Because `ocsf_events` deduplicates on `(time,id)`, redeliveries can produce duplicate rows even with deterministic IDs. >### Issue Context >Producer currently sets `received_at` using `DateTime.utc_now()` at delivery time. >### Fix Focus Areas >- elixir/serviceradar_core/lib/serviceradar/event_writer/processors/falco_events.ex[205-223] >- elixir/serviceradar_core/lib/serviceradar/event_writer/producer.ex[140-158] >- elixir/serviceradar_core/priv/repo/migrations/20260203120000_create_ocsf_events.exs[14-45] >``` > <code>ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools</code> ></details> <hr/> </details> <img src="https://www.qodo.ai/wp-content/uploads/2025/11/light-grey-line.svg" height="10%" alt="Grey Divider"> <pre>ⓘ The new review experience is currently in Beta. <a href="https://docs.qodo.ai/qodo-documentation/code-review">Learn more</a></pre> <img src="https://www.qodo.ai/wp-content/uploads/2025/11/light-grey-line.svg" height="10%" alt="Grey Divider"> <a href="https://www.qodo.ai"><img src="https://www.qodo.ai/wp-content/uploads/2025/03/qodo-logo.svg" width="80" alt="Qodo Logo"></a>
qodo-code-review[bot] commented 2026-03-03 06:56:46 +00:00 (Migrated from github.com)
Author
Owner

Imported GitHub PR review comment.

Original author: @qodo-code-review[bot]
Original URL: https://github.com/carverauto/serviceradar/pull/2986#discussion_r2876478762
Original created: 2026-03-03T06:56:46Z
Original path: elixir/serviceradar_core/config/runtime.exs
Original line: 474

Action required

1. Falco subject mismatch 🐞 Bug ✓ Correctness

This PR subscribes/routes Falco as falco.* on stream falco_events, but existing Falcosidekick
enrollment defaults and NATS permissions publish to events.falco.* (e.g., events.falco.raw). If
publishers follow the existing defaults, Falco events will be routed to the :events processor and
dropped (acknowledged) instead of persisted.
Agent Prompt
### Issue description
Falco ingestion is wired to `falco.*` subjects, but the system’s Falcosidekick enrollment/permission defaults publish to `events.falco.*`. With current defaults, Falco messages will not reach the new Falco processor and will likely be dropped/acked.

### Issue Context
- The EventWriter pipeline routes by subject prefix.
- Falcosidekick enrollment defaults define the publish subject used by deployed collectors.

### Fix Focus Areas
- elixir/serviceradar_core/lib/serviceradar/event_writer/pipeline.ex[190-246]
- elixir/serviceradar_core/config/runtime.exs[458-476]
- elixir/serviceradar_core/lib/serviceradar/event_writer/config.ex[10-34]
- elixir/serviceradar_core/lib/serviceradar/event_writer/config.ex[130-147]
- elixir/serviceradar_core/lib/serviceradar/edge/workers/provision_collector_worker.ex[214-218]
- elixir/web-ng/lib/serviceradar_web_ng_web/controllers/api/collector_enroll_controller.ex[292-297]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Imported GitHub PR review comment. Original author: @qodo-code-review[bot] Original URL: https://github.com/carverauto/serviceradar/pull/2986#discussion_r2876478762 Original created: 2026-03-03T06:56:46Z Original path: elixir/serviceradar_core/config/runtime.exs Original line: 474 --- <img src="https://www.qodo.ai/wp-content/uploads/2025/12/v2-action-required.svg" height="20" alt="Action required"> 1\. Falco subject mismatch <code>🐞 Bug</code> <code>✓ Correctness</code> <pre> This PR subscribes/routes Falco as <b><i>falco.*</i></b> on stream <b><i>falco_events</i></b>, but existing Falcosidekick enrollment defaults and NATS permissions publish to <b><i>events.falco.*</i></b> (e.g., <b><i>events.falco.raw</i></b>). If publishers follow the existing defaults, Falco events will be routed to the <b><i>:events</i></b> processor and dropped (acknowledged) instead of persisted. </pre> <details> <summary><strong>Agent Prompt</strong></summary> ``` ### Issue description Falco ingestion is wired to `falco.*` subjects, but the system’s Falcosidekick enrollment/permission defaults publish to `events.falco.*`. With current defaults, Falco messages will not reach the new Falco processor and will likely be dropped/acked. ### Issue Context - The EventWriter pipeline routes by subject prefix. - Falcosidekick enrollment defaults define the publish subject used by deployed collectors. ### Fix Focus Areas - elixir/serviceradar_core/lib/serviceradar/event_writer/pipeline.ex[190-246] - elixir/serviceradar_core/config/runtime.exs[458-476] - elixir/serviceradar_core/lib/serviceradar/event_writer/config.ex[10-34] - elixir/serviceradar_core/lib/serviceradar/event_writer/config.ex[130-147] - elixir/serviceradar_core/lib/serviceradar/edge/workers/provision_collector_worker.ex[214-218] - elixir/web-ng/lib/serviceradar_web_ng_web/controllers/api/collector_enroll_controller.ex[292-297] ``` <code>ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools</code> </details>
qodo-code-review[bot] commented 2026-03-03 06:56:46 +00:00 (Migrated from github.com)
Author
Owner

Imported GitHub PR review comment.

Original author: @qodo-code-review[bot]
Original URL: https://github.com/carverauto/serviceradar/pull/2986#discussion_r2876478766
Original created: 2026-03-03T06:56:46Z
Original path: elixir/serviceradar_core/lib/serviceradar/event_writer/processors/falco_events.ex
Original line: 53

Action required

2. Duplicates trigger alerts 🐞 Bug ✓ Correctness

Stateful alert rules are evaluated on all parsed rows even when insert_all skips duplicates
(on_conflict: :nothing). This can inflate counters and re-fire alerts on JetStream redeliveries
even though no new DB rows were inserted.
Agent Prompt
### Issue description
FalcoEvents evaluates StatefulAlertEngine for every parsed row even when the DB insert skipped some rows as duplicates. This can cause false positives / repeated alert firing under JetStream redelivery.

### Issue Context
`insert_all` uses `on_conflict: :nothing` and `returning: false`, so the code currently has no way to know which rows were inserted.

### Fix Focus Areas
- elixir/serviceradar_core/lib/serviceradar/event_writer/processors/falco_events.ex[35-55]
- elixir/serviceradar_core/lib/serviceradar/observability/stateful_alert_engine.ex[68-73]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Imported GitHub PR review comment. Original author: @qodo-code-review[bot] Original URL: https://github.com/carverauto/serviceradar/pull/2986#discussion_r2876478766 Original created: 2026-03-03T06:56:46Z Original path: elixir/serviceradar_core/lib/serviceradar/event_writer/processors/falco_events.ex Original line: 53 --- <img src="https://www.qodo.ai/wp-content/uploads/2025/12/v2-action-required.svg" height="20" alt="Action required"> 2\. Duplicates trigger alerts <code>🐞 Bug</code> <code>✓ Correctness</code> <pre> Stateful alert rules are evaluated on all parsed rows even when <b><i>insert_all</i></b> skips duplicates (<b><i>on_conflict: :nothing</i></b>). This can inflate counters and re-fire alerts on JetStream redeliveries even though no new DB rows were inserted. </pre> <details> <summary><strong>Agent Prompt</strong></summary> ``` ### Issue description FalcoEvents evaluates StatefulAlertEngine for every parsed row even when the DB insert skipped some rows as duplicates. This can cause false positives / repeated alert firing under JetStream redelivery. ### Issue Context `insert_all` uses `on_conflict: :nothing` and `returning: false`, so the code currently has no way to know which rows were inserted. ### Fix Focus Areas - elixir/serviceradar_core/lib/serviceradar/event_writer/processors/falco_events.ex[35-55] - elixir/serviceradar_core/lib/serviceradar/observability/stateful_alert_engine.ex[68-73] ``` <code>ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools</code> </details>
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
carverauto/serviceradar!3011
No description provided.