Extensible Security-Event Pipeline: Rule Suppression and Plugin-Based Enrichment
Company: Abnormal Ai
Role: Software Engineer
Category: Software Engineering Fundamentals
Interview Round: Technical Screen
You are extending an existing codebase that powers a **security-event processing platform**. Events flow through a synchronous pipeline:
- **Collection / Ingestion** — raw security events enter the system.
- **Enrichment** — each event is augmented with derived signals. Today the enrichers for specific threat dimensions (Geo-IP lookup, sender/IP *history*, etc.) are **hardcoded** directly into the pipeline code.
- **Ranking + rule-based Threat Levelling** — a set of detection *rules* evaluates each enriched event and assigns a threat level/score.
- **Alert generation** — events that trip rules above a threshold become alerts.
- **API + Database** — alerts and events are persisted and exposed through an API.
This is a single platform codebase deployed for **many different customers**. The interview combined high-level design, low-level design, and live coding on this codebase. You will extend it in two ways (the two Parts below).
### Constraints & Assumptions
- One shared platform serves all customers; you **cannot** ask a customer to fork, patch, or recompile platform code to get custom behavior.
- Enrichers and rules run **per event, synchronously** in the processing path. Exact throughput numbers were not given, but per-event overhead must stay low and predictable.
- Customers differ: some want Geo-IP enrichment, some do not; some want to silence noisy rules for a known population (e.g., their own corporate VPN egress IPs) without losing the underlying event.
- Customization should be **data/config-driven** (loaded from the database or a config service) and ideally reloadable without a full redeploy.
- Implementation language is open. Pick one (Python-style or Java-style is fine) but be precise about the **interfaces**, not just prose.
### Clarifying Questions to Ask
- What is the granularity of suppression — suppress the rule entirely, suppress only when a condition matches (a Geo-IP range, a sender), or suppress the resulting *alert*?
- Is suppression "drop the signal silently" or "keep the event, mark it suppressed" so compliance/audit can still see what was hidden and why?
- Who authors suppressions and enrichment plugins — internal engineers, or end customers through a UI/API? Where is the trust boundary, and can plugin code be untrusted?
- Roughly how many rules, enrichers, and suppression entries apply per event? (This drives the data-structure and indexing choices.)
- Does enricher ordering matter — i.e., can one enricher depend on a signal produced by another?
- Should suppressions support time bounds (maintenance windows) and expiry, or are they permanent until deleted?
### Part 1 — Rule Suppression
Implement a **Rule Suppression** feature. Operators must be able to suppress specific detection rules, where a suppression can be **scoped by conditions** — for example *"suppress rule `R` for events whose Geo-IP country is `X`"*, or a more complex predicate over event and enrichment fields. Design the suppression model and wire it into the rule-evaluation path so that a suppressed rule does **not** generate an alert — while keeping the suppression **observable and auditable** (you can still tell what was suppressed and why).
```hint Where to start
Model a suppression as a *predicate* over the `(event, enrichment)` context that is bound to a target rule id. The runtime check becomes: "for this firing rule, does any active, in-window suppression predicate match?"
```
```hint Data structure
Index suppressions by `rule_id` so a firing rule only tests the handful of suppressions that target it, instead of scanning every suppression on every event (avoid $O(\text{rules} \times \text{suppressions})$).
```
#### Clarifying Questions for this Part
- Should suppression run **before** rule evaluation (skip the work entirely, cheaper) or **after** a rule fires (full audit of what would have alerted)? What does the auditing requirement force?
- Do overlapping suppressions need precedence, and do you support time-bounded suppressions (maintenance windows) with automatic expiry?
#### What This Part Should Cover
```premium-lock What This Part Should Cover
```
### Part 2 — Configurable, Plugin-based Enrichment Layer
The enrichment logic for threats (Geo-IP, history, …) is currently hardcoded into the pipeline. Redesign the Enrichment layer so a customer can **enable, disable, reorder, or add** enrichment/detection logic **without modifying platform code**. Design a **plugin mechanism** (registration + discovery + configuration) and use the **Decorator pattern** (or justify a deliberate alternative) so customers can compose which threat-detection logic wraps the base processing — and bypass the ones they do not want. Provide the architecture *and* a concrete coding implementation of the interfaces, the registry, the composed chain, and the config-driven assembly.
```hint Pattern
Define one common `Enricher` interface. A **plugin registry** maps a plugin `name` → factory. At startup (or reload), read the customer config and build the active chain from the registry — platform code never names a specific enricher.
```
```hint Decorator vs. pipeline
The **Decorator** lets each enricher *wrap* the next, which is natural for cross-cutting concerns and for short-circuit/bypass. A plain ordered **list of enrichers** (a pipeline) is the simpler alternative — be ready to compare the two and say when each wins.
```
```hint Open/closed
A customer adds a new threat type by shipping a plugin that **self-registers** under a name; the platform discovers it via config. No `if/elif` over threat types and no platform edits — that is the open/closed principle in action.
```
#### What This Part Should Cover
```premium-lock What This Part Should Cover
```
### What a Strong Answer Covers
```premium-lock What a Strong Answer Covers
```
### Follow-up Questions
- How would you safely run **untrusted** customer plugins (sandboxing, resource/time limits, a restricted API surface)?
- How do you **hot-reload** suppressions or enricher config without dropping events or double-processing in flight?
- A customer reports that an alert which *should* have been suppressed still fired. How do you debug the composed chain and the suppression match?
- How would you **version and migrate** the plugin interface so existing customer plugins keep working across platform upgrades?
Quick Answer: This question evaluates a candidate's ability to design extensible, plugin-based software architecture for a multi-tenant processing pipeline. It tests skills in decoupling hardcoded logic into configurable components, such as enrichment steps and rule suppression, without requiring redeployment. Commonly asked to assess practical system design judgment in software engineering fundamentals, spanning both high-level architecture and low-level implementation trade-offs.